Skip to content

Commit 2b50ab0

Browse files
authored
support passing extension log level from cli (#163566)
1 parent af4b19d commit 2b50ab0

File tree

18 files changed

+125
-67
lines changed

18 files changed

+125
-67
lines changed

src/vs/platform/environment/common/argv.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export interface NativeParsedArgs {
4848
'trace-category-filter'?: string;
4949
'trace-options'?: string;
5050
'open-devtools'?: boolean;
51-
log?: string;
51+
log?: string[];
5252
logExtensionHostCommunication?: boolean;
5353
'extensions-dir'?: string;
5454
'extensions-download-dir'?: string;

src/vs/platform/environment/common/environment.ts

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export interface IEnvironmentService {
8181
// --- logging
8282
logsPath: string;
8383
logLevel?: string;
84+
extensionLogLevel?: [string, string][];
8485
verbose: boolean;
8586
isBuilt: boolean;
8687

src/vs/platform/environment/common/environmentService.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
1414
import { ExtensionKind, IDebugParams, IExtensionHostDebugParams, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
1515
import { IProductService } from 'vs/platform/product/common/productService';
1616

17+
export const EXTENSION_IDENTIFIER_WITH_LOG_REGEX = /^([^.]+\..+):(.+)$/;
18+
1719
export interface INativeEnvironmentPaths {
1820

1921
/**
@@ -216,7 +218,20 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
216218

217219
get isBuilt(): boolean { return !env['VSCODE_DEV']; }
218220
get verbose(): boolean { return !!this.args.verbose; }
219-
get logLevel(): string | undefined { return this.args.log; }
221+
222+
@memoize
223+
get logLevel(): string | undefined { return this.args.log?.find(entry => !EXTENSION_IDENTIFIER_WITH_LOG_REGEX.test(entry)); }
224+
@memoize
225+
get extensionLogLevel(): [string, string][] | undefined {
226+
const result: [string, string][] = [];
227+
for (const entry of this.args.log || []) {
228+
const matches = EXTENSION_IDENTIFIER_WITH_LOG_REGEX.exec(entry);
229+
if (matches && matches[1] && matches[2]) {
230+
result.push([matches[1], matches[2]]);
231+
}
232+
}
233+
return result.length ? result : undefined;
234+
}
220235

221236
@memoize
222237
get serviceMachineIdResource(): URI { return joinPath(URI.file(this.userDataPath), 'machineid'); }

src/vs/platform/environment/node/argv.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export const OPTIONS: OptionDescriptions<Required<NativeParsedArgs>> = {
9393

9494
'version': { type: 'boolean', cat: 't', alias: 'v', description: localize('version', "Print version.") },
9595
'verbose': { type: 'boolean', cat: 't', global: true, description: localize('verbose', "Print verbose output (implies --wait).") },
96-
'log': { type: 'string', cat: 't', args: 'level', global: true, description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") },
96+
'log': { type: 'string[]', cat: 't', args: 'level', global: true, description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'. You can also configure the log level of an extension by passing extension id and log level in the following format: '${publisher}.${name}:${logLevel}'. For example: 'vscode.csharp:trace'. Can receive one or more such entries.") },
9797
'status': { type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") },
9898
'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup.") },
9999
'prof-append-timers': { type: 'string' },

src/vs/platform/log/common/fileLog.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export class FileLoggerService extends AbstractLoggerService implements ILoggerS
147147
@ILogService logService: ILogService,
148148
@IFileService private readonly fileService: IFileService,
149149
) {
150-
super(logService.getLevel(), logService.onDidChangeLogLevel, []);
150+
super(logService.getLevel(), logService.onDidChangeLogLevel);
151151
}
152152

153153
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {

src/vs/platform/log/common/log.ts

+4-15
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export interface ILoggerService {
112112
/**
113113
* Creates a logger, or gets one if it already exists.
114114
*/
115-
createLogger(resource: URI, options?: ILoggerOptions): ILogger;
115+
createLogger(resource: URI, options?: ILoggerOptions, logLevel?: LogLevel): ILogger;
116116

117117
/**
118118
* Gets an existing logger, if any.
@@ -128,12 +128,6 @@ export interface ILoggerService {
128128
* Get log level for a logger.
129129
*/
130130
getLogLevel(resource: URI): LogLevel | undefined;
131-
132-
/**
133-
* Get default log level for a logger with given name.
134-
* @param name logger name
135-
*/
136-
getDefaultLogLevel(name: string): LogLevel;
137131
}
138132

139133
export abstract class AbstractLogger extends Disposable {
@@ -535,7 +529,6 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge
535529
constructor(
536530
private logLevel: LogLevel,
537531
onDidChangeLogLevel: Event<LogLevel>,
538-
private readonly defaultLogLevels: [string, LogLevel][]
539532
) {
540533
super();
541534
this._register(onDidChangeLogLevel(logLevel => this.setLevel(logLevel)));
@@ -549,11 +542,11 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge
549542
return this.loggerItems.get(resource)?.logger;
550543
}
551544

552-
createLogger(resource: URI, options?: ILoggerOptions): ILogger {
545+
createLogger(resource: URI, options?: ILoggerOptions, logLevel?: LogLevel): ILogger {
553546
let logger = this.loggerItems.get(resource)?.logger;
554547
if (!logger) {
555-
const logLevel = options?.always ? LogLevel.Trace : undefined;
556-
logger = this.doCreateLogger(resource, logLevel ?? (options?.name ? this.getDefaultLogLevel(options?.name) : this.logLevel), options);
548+
logLevel = options?.always ? LogLevel.Trace : logLevel;
549+
logger = this.doCreateLogger(resource, logLevel ?? this.logLevel, options);
557550
this.loggerItems.set(resource, { logger, logLevel });
558551
}
559552
return logger;
@@ -587,10 +580,6 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge
587580
return logger?.logLevel;
588581
}
589582

590-
getDefaultLogLevel(name: string): LogLevel {
591-
return this.defaultLogLevels.find(([loggerName]) => loggerName === name)?.[1] ?? this.logLevel;
592-
}
593-
594583
override dispose(): void {
595584
this.loggerItems.forEach(({ logger }) => logger.dispose());
596585
this.loggerItems.clear();

src/vs/platform/log/common/logIpc.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export class LoggerChannel implements IServerChannel {
111111
export class LoggerChannelClient extends AbstractLoggerService implements ILoggerService {
112112

113113
constructor(logLevel: LogLevel, onDidChangeLogLevel: Event<LogLevel>, private readonly channel: IChannel) {
114-
super(logLevel, onDidChangeLogLevel, []);
114+
super(logLevel, onDidChangeLogLevel);
115115
}
116116

117117
createConsoleMainLogger(): ILogger {

src/vs/platform/log/node/loggerService.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export class LoggerService extends AbstractLoggerService implements ILoggerServi
1313
constructor(
1414
@ILogService logService: ILogService
1515
) {
16-
super(logService.getLevel(), logService.onDidChangeLogLevel, []);
16+
super(logService.getLevel(), logService.onDidChangeLogLevel);
1717
}
1818

1919
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {

src/vs/server/node/serverEnvironmentService.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export interface ServerParsedArgs {
147147
'disable-telemetry'?: boolean;
148148
'file-watcher-polling'?: string;
149149

150-
'log'?: string;
150+
'log'?: string[];
151151
'logsPath'?: string;
152152

153153
'force-disable-user-env'?: boolean;

src/vs/workbench/api/common/extHostLoggerService.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class ExtHostLoggerService extends AbstractLoggerService implements ExtHo
2020
@IExtHostRpcService rpc: IExtHostRpcService,
2121
@IExtHostInitDataService initData: IExtHostInitDataService,
2222
) {
23-
super(initData.logLevel, Event.None, []);
23+
super(initData.logLevel, Event.None);
2424
this._proxy = rpc.getProxy(MainContext.MainThreadLogger);
2525
}
2626

src/vs/workbench/api/common/extHostOutput.ts

+17-8
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import type * as vscode from 'vscode';
88
import { URI } from 'vs/base/common/uri';
99
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
1010
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
11-
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
12-
import { AbstractMessageLogger, ILogger, ILoggerService, ILogService, log, LogLevel } from 'vs/platform/log/common/log';
11+
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
12+
import { AbstractMessageLogger, ILogger, ILoggerService, ILogService, log, LogLevel, parseLogLevel } from 'vs/platform/log/common/log';
1313
import { OutputChannelUpdateMode } from 'vs/workbench/services/output/common/output';
1414
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
1515
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
@@ -151,12 +151,13 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
151151
if (isString(languageId) && !languageId.trim()) {
152152
throw new Error('illegal argument `languageId`. must not be empty');
153153
}
154-
const extHostOutputChannel = log ? this.doCreateLogOutputChannel(name, extension) : this.doCreateOutputChannel(name, languageId, extension);
154+
const logLevel = this.getDefaultLogLevel(extension);
155+
const extHostOutputChannel = log ? this.doCreateLogOutputChannel(name, logLevel, extension) : this.doCreateOutputChannel(name, languageId, extension);
155156
extHostOutputChannel.then(channel => {
156157
this.channels.set(channel.id, channel);
157158
channel.visible = channel.id === this.visibleChannelId;
158159
});
159-
return log ? this.createExtHostLogOutputChannel(name, <Promise<ExtHostOutputChannel>>extHostOutputChannel) : this.createExtHostOutputChannel(name, <Promise<ExtHostOutputChannel>>extHostOutputChannel);
160+
return log ? this.createExtHostLogOutputChannel(name, logLevel, <Promise<ExtHostOutputChannel>>extHostOutputChannel) : this.createExtHostOutputChannel(name, <Promise<ExtHostOutputChannel>>extHostOutputChannel);
160161
}
161162

162163
private async doCreateOutputChannel(name: string, languageId: string | undefined, extension: IExtensionDescription): Promise<ExtHostOutputChannel> {
@@ -170,14 +171,23 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
170171
return new ExtHostOutputChannel(id, name, logger, this.proxy, extension);
171172
}
172173

173-
private async doCreateLogOutputChannel(name: string, extension: IExtensionDescription): Promise<ExtHostLogOutputChannel> {
174+
private async doCreateLogOutputChannel(name: string, logLevel: LogLevel, extension: IExtensionDescription): Promise<ExtHostLogOutputChannel> {
174175
const extensionLogDir = await this.createExtensionLogDirectory(extension);
175176
const file = this.extHostFileSystemInfo.extUri.joinPath(extensionLogDir, `${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`);
176-
const logger = this.loggerService.createLogger(file, { name });
177+
const logger = this.loggerService.createLogger(file, { name }, logLevel);
177178
const id = await this.proxy.$register(name, file, true, undefined, extension.identifier.value);
178179
return new ExtHostLogOutputChannel(id, name, logger, this.proxy, extension);
179180
}
180181

182+
private getDefaultLogLevel(extension: IExtensionDescription): LogLevel {
183+
let logLevel: LogLevel | undefined;
184+
const logLevelValue = this.initData.environment.extensionLogLevel?.find(([identifier]) => ExtensionIdentifier.equals(extension.identifier, identifier))?.[1];
185+
if (logLevelValue) {
186+
logLevel = parseLogLevel(logLevelValue);
187+
}
188+
return logLevel ?? this.logService.getLevel();
189+
}
190+
181191
private createExtensionLogDirectory(extension: IExtensionDescription): Thenable<URI> {
182192
let extensionLogDirectoryPromise = this.extensionLogDirectoryPromise.get(extension.identifier.value);
183193
if (!extensionLogDirectoryPromise) {
@@ -236,14 +246,13 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
236246
};
237247
}
238248

239-
private createExtHostLogOutputChannel(name: string, channelPromise: Promise<ExtHostOutputChannel>): vscode.LogOutputChannel {
249+
private createExtHostLogOutputChannel(name: string, logLevel: LogLevel, channelPromise: Promise<ExtHostOutputChannel>): vscode.LogOutputChannel {
240250
const disposables = new DisposableStore();
241251
const validate = () => {
242252
if (disposables.isDisposed) {
243253
throw new Error('Channel has been closed');
244254
}
245255
};
246-
let logLevel = this.logService.getLevel();
247256
const onDidChangeLogLevel = disposables.add(new Emitter<LogLevel>());
248257
channelPromise.then(channel => {
249258
disposables.add(channel);

src/vs/workbench/browser/web.api.ts

+5
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,11 @@ export interface IDevelopmentOptions {
697697
*/
698698
readonly logLevel?: LogLevel;
699699

700+
/**
701+
* Extension log level.
702+
*/
703+
readonly extensionLogLevel?: [string, LogLevel][];
704+
700705
/**
701706
* Location of a module containing extension tests to run once the workbench is open.
702707
*/

0 commit comments

Comments
 (0)