From e60bc310b8e4c15b011474571a99f3e98b663cf3 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Fri, 5 Feb 2021 17:50:59 +0100 Subject: [PATCH] move window logging to main --- src/vs/code/electron-main/app.ts | 4 +- src/vs/code/electron-main/main.ts | 5 +- src/vs/platform/log/common/log.ts | 69 ++++++++++++++++++ src/vs/platform/log/common/logIpc.ts | 43 +++++++++-- src/vs/platform/log/node/spdlogLog.ts | 67 +---------------- .../electron-sandbox/remote.contribution.ts | 5 +- .../electron-browser/desktop.main.ts | 4 +- .../log/electron-browser/logService.ts | 72 ------------------- .../log/electron-sandbox/logService.ts | 42 +++++++++++ 9 files changed, 163 insertions(+), 148 deletions(-) delete mode 100644 src/vs/workbench/services/log/electron-browser/logService.ts create mode 100644 src/vs/workbench/services/log/electron-sandbox/logService.ts diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 3f85072d571..add198ff2c1 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -21,7 +21,7 @@ import { LaunchMainService, ILaunchMainService } from 'vs/platform/launch/electr import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { ILogService } from 'vs/platform/log/common/log'; +import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { IStateService } from 'vs/platform/state/node/state'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -660,7 +660,7 @@ export class CodeApplication extends Disposable { electronIpcServer.registerChannel('storage', storageChannel); sharedProcessClient.then(client => client.registerChannel('storage', storageChannel)); - const loggerChannel = new LoggerChannel(accessor.get(ILogService)); + const loggerChannel = new LoggerChannel(accessor.get(ILogService), accessor.get(ILoggerService)); electronIpcServer.registerChannel('logger', loggerChannel); sharedProcessClient.then(client => client.registerChannel('logger', loggerChannel)); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 3da94d9c531..581d8df94ad 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -20,7 +20,7 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { ILogService, ConsoleMainLogger, MultiplexLogService, getLogLevel } from 'vs/platform/log/common/log'; +import { ILogService, ConsoleMainLogger, MultiplexLogService, getLogLevel, ILoggerService } from 'vs/platform/log/common/log'; import { StateService } from 'vs/platform/state/node/stateService'; import { IStateService } from 'vs/platform/state/node/state'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -54,6 +54,7 @@ import { coalesce, distinct } from 'vs/base/common/arrays'; import { EnvironmentMainService, IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; +import { LoggerService } from 'vs/platform/log/node/loggerService'; class ExpectedError extends Error { readonly isExpected = true; @@ -163,6 +164,8 @@ class CodeMain { const diskFileSystemProvider = new DiskFileSystemProvider(logService); fileService.registerProvider(Schemas.file, diskFileSystemProvider); + services.set(ILoggerService, new LoggerService(logService, fileService)); + services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource, fileService)); services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService)); services.set(IStateService, new SyncDescriptor(StateService)); diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 5301e86a089..79e1d362337 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -78,6 +78,75 @@ export abstract class AbstractLogger extends Disposable { } +export abstract class AbstractMessageLogger extends AbstractLogger implements ILogger { + + protected abstract log(level: LogLevel, message: string): void; + + trace(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Trace) { + this.log(LogLevel.Trace, this.format([message, ...args])); + } + } + + debug(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Debug) { + this.log(LogLevel.Debug, this.format([message, ...args])); + } + } + + info(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Info) { + this.log(LogLevel.Info, this.format([message, ...args])); + } + } + + warn(message: string, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Warning) { + this.log(LogLevel.Warning, this.format([message, ...args])); + } + } + + error(message: string | Error, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Error) { + + if (message instanceof Error) { + const array = Array.prototype.slice.call(arguments) as any[]; + array[0] = message.stack; + this.log(LogLevel.Error, this.format(array)); + } else { + this.log(LogLevel.Error, this.format([message, ...args])); + } + } + } + + critical(message: string | Error, ...args: any[]): void { + if (this.getLevel() <= LogLevel.Critical) { + this.log(LogLevel.Critical, this.format([message, ...args])); + } + } + + flush(): void { } + + private format(args: any): string { + let result = ''; + + for (let i = 0; i < args.length; i++) { + let a = args[i]; + + if (typeof a === 'object') { + try { + a = JSON.stringify(a); + } catch (e) { } + } + + result += (i > 0 ? ' ' : '') + a; + } + + return result; + } +} + + export class ConsoleMainLogger extends AbstractLogger implements ILogger { private useColors: boolean; diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts index e97ece3ca01..8d42e71591f 100644 --- a/src/vs/platform/log/common/logIpc.ts +++ b/src/vs/platform/log/common/logIpc.ts @@ -4,14 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { LogLevel, ILogService, LogService } from 'vs/platform/log/common/log'; +import { LogLevel, ILogService, LogService, ILoggerService, ILogger, AbstractMessageLogger } from 'vs/platform/log/common/log'; import { Event } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; export class LoggerChannel implements IServerChannel { onDidChangeLogLevel: Event; - constructor(private service: ILogService) { + constructor( + private service: ILogService, + private readonly loggerService: ILoggerService, + ) { this.onDidChangeLogLevel = Event.buffer(service.onDidChangeLogLevel, true); } @@ -23,10 +27,12 @@ export class LoggerChannel implements IServerChannel { throw new Error(`Event not found: ${event}`); } - call(_: unknown, command: string, arg?: any): Promise { + async call(_: unknown, command: string, arg?: any): Promise { switch (command) { - case 'setLevel': this.service.setLevel(arg); return Promise.resolve(); - case 'consoleLog': this.consoleLog(arg[0], arg[1]); return Promise.resolve(); + case 'setLevel': return this.service.setLevel(arg); + case 'consoleLog': return this.consoleLog(arg[0], arg[1]); + case 'initLogger': this.getLogger(URI.revive(arg[0])); return; + case 'log': return this.log(URI.revive(arg[0]), arg[1], arg[2]); } throw new Error(`Call not found: ${command}`); @@ -49,6 +55,23 @@ export class LoggerChannel implements IServerChannel { consoleFn.call(console, ...args); } + + private getLogger(file: URI): ILogger { + return this.loggerService.getLogger(file); + } + + private log(file: URI, level: LogLevel, message: string): void { + const logger = this.getLogger(file); + switch (level) { + case LogLevel.Trace: logger.trace(message); break; + case LogLevel.Debug: logger.debug(message); break; + case LogLevel.Info: logger.info(message); break; + case LogLevel.Warning: logger.warn(message); break; + case LogLevel.Error: logger.error(message); break; + case LogLevel.Critical: logger.critical(message); break; + default: throw new Error('Invalid log level'); + } + } } export class LoggerChannelClient { @@ -70,6 +93,16 @@ export class LoggerChannelClient { consoleLog(severity: string, args: string[]): void { this.channel.call('consoleLog', [severity, args]); } + + getLogger(file: URI): ILogger { + this.channel.call('initLogger', [file]); + const that = this; + return new class extends AbstractMessageLogger { + protected log(level: LogLevel, message: string) { + that.channel.call('log', [file, level, message]); + } + }; + } } export class FollowerLogService extends LogService implements ILogService { diff --git a/src/vs/platform/log/node/spdlogLog.ts b/src/vs/platform/log/node/spdlogLog.ts index 55f70e7dc0f..f3e566c5c21 100644 --- a/src/vs/platform/log/node/spdlogLog.ts +++ b/src/vs/platform/log/node/spdlogLog.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'vs/base/common/path'; -import { LogLevel, AbstractLogger, ILogger } from 'vs/platform/log/common/log'; +import { LogLevel, ILogger, AbstractMessageLogger } from 'vs/platform/log/common/log'; import * as spdlog from 'spdlog'; import { ByteSize } from 'vs/platform/files/common/files'; @@ -43,7 +43,7 @@ function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): v } } -export class SpdLogLogger extends AbstractLogger implements ILogger { +export class SpdLogLogger extends AbstractMessageLogger implements ILogger { private buffer: ILog[] = []; private _loggerCreationPromise: Promise | undefined = undefined; @@ -77,7 +77,7 @@ export class SpdLogLogger extends AbstractLogger implements ILogger { return this._loggerCreationPromise; } - private _log(level: LogLevel, message: string): void { + protected log(level: LogLevel, message: string): void { if (this._logger) { log(this._logger, level, message); } else if (this.getLevel() <= level) { @@ -85,49 +85,6 @@ export class SpdLogLogger extends AbstractLogger implements ILogger { } } - trace(message: string, ...args: any[]): void { - if (this.getLevel() <= LogLevel.Trace) { - this._log(LogLevel.Trace, this.format([message, ...args])); - } - } - - debug(message: string, ...args: any[]): void { - if (this.getLevel() <= LogLevel.Debug) { - this._log(LogLevel.Debug, this.format([message, ...args])); - } - } - - info(message: string, ...args: any[]): void { - if (this.getLevel() <= LogLevel.Info) { - this._log(LogLevel.Info, this.format([message, ...args])); - } - } - - warn(message: string, ...args: any[]): void { - if (this.getLevel() <= LogLevel.Warning) { - this._log(LogLevel.Warning, this.format([message, ...args])); - } - } - - error(message: string | Error, ...args: any[]): void { - if (this.getLevel() <= LogLevel.Error) { - - if (message instanceof Error) { - const array = Array.prototype.slice.call(arguments) as any[]; - array[0] = message.stack; - this._log(LogLevel.Error, this.format(array)); - } else { - this._log(LogLevel.Error, this.format([message, ...args])); - } - } - } - - critical(message: string | Error, ...args: any[]): void { - if (this.getLevel() <= LogLevel.Critical) { - this._log(LogLevel.Critical, this.format([message, ...args])); - } - } - flush(): void { if (this._logger) { this._logger.flush(); @@ -151,22 +108,4 @@ export class SpdLogLogger extends AbstractLogger implements ILogger { this._logger = undefined; } } - - private format(args: any): string { - let result = ''; - - for (let i = 0; i < args.length; i++) { - let a = args[i]; - - if (typeof a === 'object') { - try { - a = JSON.stringify(a); - } catch (e) { } - } - - result += (i > 0 ? ' ' : '') + a; - } - - return result; - } } diff --git a/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts index 9539d660d85..0b9e209d249 100644 --- a/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts @@ -16,7 +16,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { Schemas } from 'vs/base/common/network'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { ILogService } from 'vs/platform/log/common/log'; +import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; import { DownloadServiceChannel } from 'vs/platform/download/common/downloadIpc'; import { LoggerChannel } from 'vs/platform/log/common/logIpc'; import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals'; @@ -34,13 +34,14 @@ class RemoteChannelsContribution implements IWorkbenchContribution { constructor( @ILogService logService: ILogService, + @ILogService loggerService: ILoggerService, @IRemoteAgentService remoteAgentService: IRemoteAgentService, @IDownloadService downloadService: IDownloadService ) { const connection = remoteAgentService.getConnection(); if (connection) { connection.registerChannel('download', new DownloadServiceChannel(downloadService)); - connection.registerChannel('logger', new LoggerChannel(logService)); + connection.registerChannel('logger', new LoggerChannel(logService, loggerService)); } } } diff --git a/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts index 465542118c5..8e89ce8d535 100644 --- a/src/vs/workbench/electron-browser/desktop.main.ts +++ b/src/vs/workbench/electron-browser/desktop.main.ts @@ -44,7 +44,7 @@ import { FileUserDataProvider } from 'vs/workbench/services/userData/common/file import { basename } from 'vs/base/common/path'; import { IProductService } from 'vs/platform/product/common/productService'; import product from 'vs/platform/product/common/product'; -import { NativeLogService } from 'vs/workbench/services/log/electron-browser/logService'; +import { NativeLogService } from 'vs/workbench/services/log/electron-sandbox/logService'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { NativeHostService } from 'vs/platform/native/electron-sandbox/nativeHostService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; @@ -164,7 +164,7 @@ class DesktopMain extends Disposable { serviceCollection.set(IProductService, this.productService); // Log - const logService = this._register(new NativeLogService(this.configuration.windowId, mainProcessService, this.environmentService)); + const logService = this._register(new NativeLogService(mainProcessService, this.environmentService)); serviceCollection.set(ILogService, logService); // Remote diff --git a/src/vs/workbench/services/log/electron-browser/logService.ts b/src/vs/workbench/services/log/electron-browser/logService.ts deleted file mode 100644 index 038bf46b550..00000000000 --- a/src/vs/workbench/services/log/electron-browser/logService.ts +++ /dev/null @@ -1,72 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { LogService, ILogService, ConsoleLogger, MultiplexLogService, ILogger, AdapterLogger } from 'vs/platform/log/common/log'; -import { BufferLogService } from 'vs/platform/log/common/bufferLog'; -import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; -import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService'; -import { LoggerChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; -import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; - -export class NativeLogService extends LogService { - - private readonly bufferSpdLogService: BufferLogService | undefined; - private readonly windowId: number; - private readonly environmentService: INativeWorkbenchEnvironmentService; - - constructor(windowId: number, mainProcessService: IMainProcessService, environmentService: INativeWorkbenchEnvironmentService) { - - const disposables = new DisposableStore(); - const loggerClient = new LoggerChannelClient(mainProcessService.getChannel('logger')); - let bufferSpdLogService: BufferLogService | undefined; - - // Extension development test CLI: forward everything to main side - const loggers: ILogger[] = []; - if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) { - loggers.push( - disposables.add(new AdapterLogger({ log: (type, args) => loggerClient.consoleLog(type, args) }, environmentService.configuration.logLevel)) - ); - } - - // Normal logger: spdylog and console - else { - bufferSpdLogService = disposables.add(new BufferLogService(environmentService.configuration.logLevel)); - loggers.push( - disposables.add(new ConsoleLogger(environmentService.configuration.logLevel)), - bufferSpdLogService - ); - } - - const multiplexLogger = disposables.add(new MultiplexLogService(loggers)); - const followerLogger = disposables.add(new FollowerLogService(loggerClient, multiplexLogger)); - super(followerLogger); - - this.bufferSpdLogService = bufferSpdLogService; - this.windowId = windowId; - this.environmentService = environmentService; - - this._register(disposables); - } - - init(): void { - if (this.bufferSpdLogService) { - this.bufferSpdLogService.logger = this._register(new SpdLogLogger(`renderer${this.windowId}`, this.environmentService.logsPath, this.getLevel())); - this.trace('Created Spdlogger'); - } - } -} - -class NativeLogServiceInitContribution implements IWorkbenchContribution { - constructor(@ILogService logService: ILogService) { - if (logService instanceof NativeLogService) { - logService.init(); - } - } -} -Registry.as(Extensions.Workbench).registerWorkbenchContribution(NativeLogServiceInitContribution, LifecyclePhase.Restored); diff --git a/src/vs/workbench/services/log/electron-sandbox/logService.ts b/src/vs/workbench/services/log/electron-sandbox/logService.ts new file mode 100644 index 00000000000..a7538d944f0 --- /dev/null +++ b/src/vs/workbench/services/log/electron-sandbox/logService.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LogService, ConsoleLogger, MultiplexLogService, ILogger, AdapterLogger } from 'vs/platform/log/common/log'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; +import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService'; +import { LoggerChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; +import { DisposableStore } from 'vs/base/common/lifecycle'; + +export class NativeLogService extends LogService { + + constructor(mainProcessService: IMainProcessService, environmentService: INativeWorkbenchEnvironmentService) { + + const disposables = new DisposableStore(); + const loggerClient = new LoggerChannelClient(mainProcessService.getChannel('logger')); + + // Extension development test CLI: forward everything to main side + const loggers: ILogger[] = []; + if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) { + loggers.push( + disposables.add(new AdapterLogger({ log: (type, args) => loggerClient.consoleLog(type, args) }, environmentService.configuration.logLevel)) + ); + } + + // Normal logger: spdylog and console + else { + loggers.push( + disposables.add(new ConsoleLogger(environmentService.configuration.logLevel)), + disposables.add(loggerClient.getLogger(environmentService.logFile)) + ); + } + + const multiplexLogger = disposables.add(new MultiplexLogService(loggers)); + const followerLogger = disposables.add(new FollowerLogService(loggerClient, multiplexLogger)); + super(followerLogger); + + this._register(disposables); + } + +}