Log improvements (#163532)

* - expose log level in the proposed api
- ability to set log level per logger

* fix tests
This commit is contained in:
Sandeep Somavarapu
2022-10-13 12:48:52 +02:00
committed by GitHub
parent a78f7af399
commit 894aa9a7a7
30 changed files with 421 additions and 109 deletions

View File

@@ -5,29 +5,41 @@
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
import { ILoggerOptions, ILoggerService, ILogService, log, LogLevel } from 'vs/platform/log/common/log';
import { IDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainThreadLoggerShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { UriComponents, URI } from 'vs/base/common/uri';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ILogLevelService } from 'vs/workbench/contrib/logs/common/logLevelService';
import { IOutputService } from 'vs/workbench/services/output/common/output';
import { localExtHostLog, remoteExtHostLog, webWorkerExtHostLog } from 'vs/workbench/services/extensions/common/extensions';
@extHostNamedCustomer(MainContext.MainThreadLogger)
export class MainThreadLoggerService implements MainThreadLoggerShape {
private readonly _logListener: IDisposable;
private readonly disposables = new DisposableStore();
constructor(
extHostContext: IExtHostContext,
@ILogService logService: ILogService,
@ILoggerService private readonly _loggerService: ILoggerService,
@ILoggerService private readonly loggerService: ILoggerService,
@ILogLevelService extensionLoggerService: ILogLevelService,
@IOutputService outputService: IOutputService,
) {
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostLogLevelServiceShape);
this._logListener = logService.onDidChangeLogLevel(level => proxy.$setLevel(level));
this.disposables.add(logService.onDidChangeLogLevel(level => proxy.$setLevel(level)));
this.disposables.add(extensionLoggerService.onDidChangeLogLevel(({ id, logLevel }) => {
const channel = outputService.getChannelDescriptor(id);
const resource = channel?.log ? channel.file : undefined;
if (resource && (channel?.extensionId || id === localExtHostLog || id === remoteExtHostLog || id === webWorkerExtHostLog)) {
proxy.$setLevel(logLevel, resource);
}
}));
}
$log(file: UriComponents, messages: [LogLevel, string][]): void {
const logger = this._loggerService.getLogger(URI.revive(file));
const logger = this.loggerService.getLogger(URI.revive(file));
if (!logger) {
throw new Error('Create the logger before logging');
}
@@ -37,11 +49,11 @@ export class MainThreadLoggerService implements MainThreadLoggerShape {
}
async $createLogger(file: UriComponents, options?: ILoggerOptions): Promise<void> {
this._loggerService.createLogger(URI.revive(file), options);
this.loggerService.createLogger(URI.revive(file), options);
}
dispose(): void {
this._logListener.dispose();
this.disposables.dispose();
}
}

View File

@@ -59,7 +59,7 @@ import { IExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations'
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { ILoggerService, ILogService } from 'vs/platform/log/common/log';
import { ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
@@ -364,6 +364,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
get uiKind() {
return initData.uiKind;
},
get logLevel() {
checkProposedApiEnabled(extension, 'extensionLog');
return extHostLogService.getLevel();
},
get onDidChangeLogLevel() {
checkProposedApiEnabled(extension, 'extensionLog');
return extHostLogService.onDidChangeLogLevel;
}
};
if (!initData.environment.extensionTestsLocationURI) {
@@ -1383,7 +1391,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
TabInputWebview: extHostTypes.WebviewEditorTabInput,
TabInputTerminal: extHostTypes.TerminalEditorTabInput,
TabInputInteractiveWindow: extHostTypes.InteractiveWindowInput,
TerminalExitReason: extHostTypes.TerminalExitReason
TerminalExitReason: extHostTypes.TerminalExitReason,
LogLevel: LogLevel,
};
};
}

View File

@@ -1944,7 +1944,7 @@ export interface ExtHostWindowShape {
}
export interface ExtHostLogLevelServiceShape {
$setLevel(level: LogLevel): void;
$setLevel(level: LogLevel, resource?: UriComponents): void;
}
export interface MainThreadLoggerShape {

View File

@@ -7,27 +7,29 @@ import { ILogger, ILoggerOptions, AbstractMessageLogger, LogLevel, AbstractLogge
import { MainThreadLoggerShape, MainContext, ExtHostLogLevelServiceShape as ExtHostLogLevelServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { URI } from 'vs/base/common/uri';
import { Emitter } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { Event } from 'vs/base/common/event';
import { isUndefined } from 'vs/base/common/types';
export class ExtHostLoggerService extends AbstractLoggerService implements ExtHostLogLevelServiceShape {
declare readonly _serviceBrand: undefined;
private readonly _onDidChangeLogLevel: Emitter<LogLevel>;
private readonly _proxy: MainThreadLoggerShape;
constructor(
@IExtHostRpcService rpc: IExtHostRpcService,
@IExtHostInitDataService initData: IExtHostInitDataService,
) {
const emitter = new Emitter<LogLevel>();
super(initData.logLevel, emitter.event);
super(initData.logLevel, Event.None, []);
this._proxy = rpc.getProxy(MainContext.MainThreadLogger);
this._onDidChangeLogLevel = this._register(emitter);
}
$setLevel(level: LogLevel): void {
this._onDidChangeLogLevel.fire(level);
$setLevel(level: LogLevel, resource?: UriComponents): void {
if (resource) {
this.setLevel(URI.revive(resource), level);
} else if (!isUndefined(level)) {
this.setLevel(level);
}
}
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {

View File

@@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { AbstractMessageLogger, ILogger, ILoggerService, log, LogLevel } from 'vs/platform/log/common/log';
import { AbstractMessageLogger, ILogger, ILoggerService, ILogService, log, LogLevel } from 'vs/platform/log/common/log';
import { OutputChannelUpdateMode } from 'vs/workbench/services/output/common/output';
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
@@ -18,6 +18,9 @@ import { toLocalISOString } from 'vs/base/common/date';
import { VSBuffer } from 'vs/base/common/buffer';
import { isString } from 'vs/base/common/types';
import { FileSystemProviderErrorCode, toFileSystemProviderErrorCode } from 'vs/platform/files/common/files';
import { Emitter } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOutputChannel {
@@ -38,6 +41,10 @@ class ExtHostOutputChannel extends AbstractMessageLogger implements vscode.LogOu
this._register(logger.onDidChangeLogLevel(level => this.setLevel(level)));
}
get logLevel(): LogLevel {
return this.logger.getLevel();
}
appendLine(value: string): void {
this.append(value + '\n');
}
@@ -118,6 +125,7 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
@IExtHostConsumerFileSystem private readonly extHostFileSystem: IExtHostConsumerFileSystem,
@IExtHostFileSystemInfo private readonly extHostFileSystemInfo: IExtHostFileSystemInfo,
@ILoggerService private readonly loggerService: ILoggerService,
@ILogService private readonly logService: ILogService,
) {
this.proxy = extHostRpc.getProxy(MainContext.MainThreadOutputService);
this.outputsLocation = this.extHostFileSystemInfo.extUri.joinPath(initData.logsLocation, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
@@ -136,6 +144,9 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
throw new Error('illegal argument `name`. must not be falsy');
}
const log = typeof options === 'object' && options.log;
if (log) {
checkProposedApiEnabled(extension, 'extensionLog');
}
const languageId = isString(options) ? options : undefined;
if (isString(languageId) && !languageId.trim()) {
throw new Error('illegal argument `languageId`. must not be empty');
@@ -226,14 +237,25 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
}
private createExtHostLogOutputChannel(name: string, channelPromise: Promise<ExtHostOutputChannel>): vscode.LogOutputChannel {
let disposed = false;
const disposables = new DisposableStore();
const validate = () => {
if (disposed) {
if (disposables.isDisposed) {
throw new Error('Channel has been closed');
}
};
let logLevel = this.logService.getLevel();
const onDidChangeLogLevel = disposables.add(new Emitter<LogLevel>());
channelPromise.then(channel => {
disposables.add(channel);
disposables.add(channel.onDidChangeLogLevel(e => {
logLevel = e;
onDidChangeLogLevel.fire(e);
}));
});
return {
...this.createExtHostOutputChannel(name, channelPromise),
get logLevel() { return logLevel; },
onDidChangeLogLevel: onDidChangeLogLevel.event,
trace(value: string, ...args: any[]): void {
validate();
channelPromise.then(channel => channel.trace(value, ...args));
@@ -255,8 +277,7 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
channelPromise.then(channel => channel.error(value, ...args));
},
dispose(): void {
disposed = true;
channelPromise.then(channel => channel.dispose());
disposables.dispose();
}
};
}