diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 5053e79026a08..87e9115694b25 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -48,8 +48,8 @@ import { MessagePortMainProcessService } from 'vs/platform/ipc/electron-browser/ import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { NativeLanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; -import { ConsoleLogger, ILoggerService, ILogService, MultiplexLogService } from 'vs/platform/log/common/log'; -import { FollowerLogService, LoggerChannelClient, LogLevelChannel, LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; +import { ConsoleLogger, ILoggerService, ILogService } from 'vs/platform/log/common/log'; +import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -115,6 +115,7 @@ import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/co import { ExtensionsContributions } from 'vs/code/electron-browser/sharedProcess/contrib/extensions'; import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/electron-sandbox/extensionsProfileScannerService'; import { localize } from 'vs/nls'; +import { LogService } from 'vs/platform/log/common/logService'; class SharedProcessMain extends Disposable { @@ -216,17 +217,13 @@ class SharedProcessMain extends Disposable { services.set(INativeEnvironmentService, environmentService); // Logger - const logLevelClient = new LogLevelChannelClient(this.server.getChannel('logLevel', mainRouter)); - const loggerService = new LoggerChannelClient(undefined, this.configuration.logLevel, logLevelClient.onDidChangeLogLevel, this.configuration.loggers, mainProcessService.getChannel('logger')); + const loggerService = new LoggerChannelClient(undefined, this.configuration.logLevel, this.configuration.loggers, mainProcessService.getChannel('logger')); services.set(ILoggerService, loggerService); // Log - const multiplexLogger = this._register(new MultiplexLogService([ - this._register(new ConsoleLogger(this.configuration.logLevel)), - this._register(loggerService.createLogger(joinPath(URI.file(environmentService.logsPath), 'sharedprocess.log'), { id: 'sharedLog', name: localize('sharedLog', "Shared") })) - ])); - - const logService = this._register(new FollowerLogService(logLevelClient, multiplexLogger)); + const logger = this._register(loggerService.createLogger(joinPath(URI.file(environmentService.logsPath), 'sharedprocess.log'), { id: 'sharedLog', name: localize('sharedLog', "Shared") })); + const consoleLogger = this._register(new ConsoleLogger(this.configuration.logLevel)); + const logService = this._register(new LogService(logger, [consoleLogger])); services.set(ILogService, logService); // Lifecycle @@ -374,11 +371,11 @@ class SharedProcessMain extends Disposable { shortGraceTime: LocalReconnectConstants.ShortGraceTime, scrollback: configurationService.getValue(TerminalSettingId.PersistentSessionScrollback) ?? 100 }, + localize('ptyHost', "Pty Host"), configurationService, environmentService, logService, - loggerService, - uriIdentityService + loggerService ); ptyHostService.initialize(); @@ -399,10 +396,6 @@ class SharedProcessMain extends Disposable { private initChannels(accessor: ServicesAccessor): void { - // Log Level - const logLevelChannel = new LogLevelChannel(accessor.get(ILogService), accessor.get(ILoggerService)); - this.server.registerChannel('logLevel', logLevelChannel); - // Extensions Management const channel = new ExtensionManagementChannel(accessor.get(IExtensionManagementService), () => null); this.server.registerChannel('extensions', channel); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 1df6eaf9becce..1b502641a3a13 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -58,8 +58,7 @@ import { IIssueMainService, IssueMainService } from 'vs/platform/issue/electron- import { IKeyboardLayoutMainService, KeyboardLayoutMainService } from 'vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService'; import { ILaunchMainService, LaunchMainService } from 'vs/platform/launch/electron-main/launchMainService'; import { ILifecycleMainService, LifecycleMainPhase, ShutdownReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; -import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; -import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; +import { ILogService } from 'vs/platform/log/common/log'; import { IMenubarMainService, MenubarMainService } from 'vs/platform/menubar/electron-main/menubarMainService'; import { INativeHostMainService, NativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -800,11 +799,6 @@ export class CodeApplication extends Disposable { const externalTerminalChannel = ProxyChannel.fromService(accessor.get(IExternalTerminalMainService)); mainProcessElectronServer.registerChannel('externalTerminal', externalTerminalChannel); - // Log Level (main & shared process) - const logLevelChannel = new LogLevelChannel(accessor.get(ILogService), accessor.get(ILoggerService)); - mainProcessElectronServer.registerChannel('logLevel', logLevelChannel); - sharedProcessClient.then(client => client.registerChannel('logLevel', logLevelChannel)); - // Logger const loggerChannel = new LoggerChannel(accessor.get(ILoggerMainService),); mainProcessElectronServer.registerChannel('logger', loggerChannel); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 1f47c50846bb9..7774e605a4861 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -44,8 +44,8 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILaunchMainService } from 'vs/platform/launch/electron-main/launchMainService'; import { ILifecycleMainService, LifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; -import { BufferLogService } from 'vs/platform/log/common/bufferLog'; -import { ConsoleMainLogger, getLogLevel, ILoggerService, ILogService, MultiplexLogService } from 'vs/platform/log/common/log'; +import { BufferLogger } from 'vs/platform/log/common/bufferLog'; +import { ConsoleMainLogger, getLogLevel, ILoggerService, ILogService } from 'vs/platform/log/common/log'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol'; @@ -69,6 +69,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity' import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; import { PROFILES_ENABLEMENT_CONFIG } from 'vs/platform/userDataProfile/common/userDataProfile'; import { ILoggerMainService, LoggerMainService } from 'vs/platform/log/electron-main/loggerService'; +import { LogService } from 'vs/platform/log/common/logService'; /** * The main VS Code entry point. @@ -145,7 +146,7 @@ class CodeMain { } } - private createServices(): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateMainService, BufferLogService, IProductService, UserDataProfilesMainService] { + private createServices(): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateMainService, BufferLogger, IProductService, UserDataProfilesMainService] { const services = new ServiceCollection(); const disposables = new DisposableStore(); process.once('exit', () => disposables.dispose()); @@ -159,11 +160,15 @@ class CodeMain { const instanceEnvironment = this.patchEnvironment(environmentMainService); // Patch `process.env` with the instance's environment services.set(IEnvironmentMainService, environmentMainService); + // Logger + const loggerService = new LoggerMainService(getLogLevel(environmentMainService)); + services.set(ILoggerMainService, loggerService); + // Log: We need to buffer the spdlog logs until we are sure // we are the only instance running, otherwise we'll have concurrent // log file access on Windows (https://github.com/microsoft/vscode/issues/41218) - const bufferLogService = new BufferLogService(); - const logService = disposables.add(new MultiplexLogService([new ConsoleMainLogger(getLogLevel(environmentMainService)), bufferLogService])); + const bufferLogger = new BufferLogger(loggerService.getLogLevel()); + const logService = disposables.add(new LogService(bufferLogger, [new ConsoleMainLogger(loggerService.getLogLevel())])); services.set(ILogService, logService); // Files @@ -176,9 +181,6 @@ class CodeMain { const uriIdentityService = new UriIdentityService(fileService); services.set(IUriIdentityService, uriIdentityService); - // Logger - services.set(ILoggerMainService, new LoggerMainService(logService)); - // State const stateMainService = new StateMainService(environmentMainService, logService, fileService); services.set(IStateMainService, stateMainService); @@ -215,7 +217,7 @@ class CodeMain { // Protocol (instantiated early and not using sync descriptor for security reasons) services.set(IProtocolMainService, new ProtocolMainService(environmentMainService, userDataProfilesMainService, logService)); - return [new InstantiationService(services, true), instanceEnvironment, environmentMainService, configurationService, stateMainService, bufferLogService, productService, userDataProfilesMainService]; + return [new InstantiationService(services, true), instanceEnvironment, environmentMainService, configurationService, stateMainService, bufferLogger, productService, userDataProfilesMainService]; } private patchEnvironment(environmentMainService: IEnvironmentMainService): IProcessEnvironment { diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index a16f65955aed9..c04d9d083b521 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -39,7 +39,7 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { NativeLanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; -import { ConsoleLogger, getLogLevel, ILogger, ILogService, LogLevel, MultiplexLogService } from 'vs/platform/log/common/log'; +import { ConsoleLogger, getLogLevel, ILogger, ILogService, LogLevel } from 'vs/platform/log/common/log'; import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; import { FilePolicyService } from 'vs/platform/policy/common/filePolicyService'; import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy'; @@ -62,6 +62,7 @@ import { IUserDataProfilesService, PROFILES_ENABLEMENT_CONFIG } from 'vs/platfor import { UserDataProfilesService } from 'vs/platform/userDataProfile/node/userDataProfile'; import { resolveMachineId } from 'vs/platform/telemetry/node/telemetryUtils'; import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/node/extensionsProfileScannerService'; +import { LogService } from 'vs/platform/log/common/logService'; class CliMain extends Disposable { @@ -126,13 +127,13 @@ class CliMain extends Disposable { // Log const logLevel = getLogLevel(environmentService); - const loggers: ILogger[] = []; - loggers.push(new SpdLogLogger('cli', join(environmentService.logsPath, 'cli.log'), true, false, logLevel)); + const spdLogLogger = new SpdLogLogger('cli', join(environmentService.logsPath, 'cli.log'), true, false, logLevel); + const otherLoggers: ILogger[] = []; if (logLevel === LogLevel.Trace) { - loggers.push(new ConsoleLogger(logLevel)); + otherLoggers.push(new ConsoleLogger(logLevel)); } - const logService = this._register(new MultiplexLogService(loggers)); + const logService = this._register(new LogService(spdLogLogger, otherLoggers)); services.set(ILogService, logService); // Files diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index c8258b9923ed4..91a8c8313b2ee 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -49,7 +49,7 @@ import { StandaloneServicesNLS } from 'vs/editor/common/standaloneStrings'; import { ClassifiedEvent, StrictPropertyCheck, OmitMetadata, IGDPRProperty } from 'vs/platform/telemetry/common/gdprTypings'; import { basename } from 'vs/base/common/resources'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { ConsoleLogger, ILogService, LogService } from 'vs/platform/log/common/log'; +import { ConsoleLogger, ILogService } from 'vs/platform/log/common/log'; import { IWorkspaceTrustManagementService, IWorkspaceTrustTransitionParticipant, IWorkspaceTrustUriInfo } from 'vs/platform/workspace/common/workspaceTrust'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; @@ -90,6 +90,7 @@ import 'vs/editor/common/services/languageFeaturesService'; import { DefaultConfiguration } from 'vs/platform/configuration/common/configurations'; import { WorkspaceEdit } from 'vs/editor/common/languages'; import { AudioCue, IAudioCueService, Sound } from 'vs/platform/audioCues/browser/audioCueService'; +import { LogService } from 'vs/platform/log/common/logService'; class SimpleModel implements IResolvedTextEditorModel { diff --git a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts index 5c77ec6f01d6b..928d90f7a40bd 100644 --- a/src/vs/platform/backup/test/electron-main/backupMainService.test.ts +++ b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts @@ -20,11 +20,12 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { EnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; import { HotExitConfiguration } from 'vs/platform/files/common/files'; -import { ConsoleMainLogger, LogService } from 'vs/platform/log/common/log'; +import { ConsoleMainLogger } from 'vs/platform/log/common/log'; import product from 'vs/platform/product/common/product'; import { IFolderBackupInfo, isFolderBackupInfo, IWorkspaceBackupInfo } from 'vs/platform/backup/common/backup'; import { IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; import { InMemoryTestStateMainService } from 'vs/platform/test/electron-main/workbenchTestServices'; +import { LogService } from 'vs/platform/log/common/logService'; flakySuite('BackupMainService', () => { diff --git a/src/vs/platform/log/common/bufferLog.ts b/src/vs/platform/log/common/bufferLog.ts index 4756c8a17ed65..5d8f31089fbb4 100644 --- a/src/vs/platform/log/common/bufferLog.ts +++ b/src/vs/platform/log/common/bufferLog.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { AbstractMessageLogger, DEFAULT_LOG_LEVEL, ILogger, ILogService, log, LogLevel } from 'vs/platform/log/common/log'; +import { AbstractMessageLogger, DEFAULT_LOG_LEVEL, ILogger, log, LogLevel } from 'vs/platform/log/common/log'; interface ILog { level: LogLevel; message: string; } -export class BufferLogService extends AbstractMessageLogger implements ILogService { +export class BufferLogger extends AbstractMessageLogger { declare readonly _serviceBrand: undefined; private buffer: ILog[] = []; diff --git a/src/vs/platform/log/common/fileLog.ts b/src/vs/platform/log/common/fileLog.ts index 3e4f23c77586b..38fbd54b3e3b5 100644 --- a/src/vs/platform/log/common/fileLog.ts +++ b/src/vs/platform/log/common/fileLog.ts @@ -8,8 +8,8 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { basename, dirname, joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { ByteSize, FileOperationError, FileOperationResult, IFileService, whenProviderRegistered } from 'vs/platform/files/common/files'; -import { BufferLogService } from 'vs/platform/log/common/bufferLog'; -import { AbstractLoggerService, AbstractMessageLogger, ILogger, ILoggerOptions, ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log'; +import { BufferLogger } from 'vs/platform/log/common/bufferLog'; +import { AbstractLoggerService, AbstractMessageLogger, ILogger, ILoggerOptions, ILoggerService, LogLevel } from 'vs/platform/log/common/log'; const MAX_FILE_SIZE = 5 * ByteSize.MB; @@ -98,15 +98,15 @@ export class FileLogger extends AbstractMessageLogger implements ILogger { export class FileLoggerService extends AbstractLoggerService implements ILoggerService { constructor( - @ILogService logService: ILogService, + logLevel: LogLevel, @IFileService private readonly fileService: IFileService, ) { - super(logService.getLevel(), logService.onDidChangeLogLevel); + super(logLevel); } protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger { - const logger = new BufferLogService(logLevel); - whenProviderRegistered(resource, this.fileService).then(() => (logger).logger = new FileLogger(resource, logger.getLevel(), !!options?.donotUseFormatters, this.fileService)); + const logger = new BufferLogger(logLevel); + whenProviderRegistered(resource, this.fileService).then(() => logger.logger = new FileLogger(resource, logger.getLevel(), !!options?.donotUseFormatters, this.fileService)); return logger; } } diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 2fe108a6122a7..f85f95c1be0ab 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -8,7 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { isWindows } from 'vs/base/common/platform'; -import { Mutable } from 'vs/base/common/types'; +import { Mutable, isNumber } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -20,6 +20,10 @@ function now(): string { return new Date().toISOString(); } +export function isLogLevel(thing: unknown): thing is LogLevel { + return isNumber(thing); +} + export enum LogLevel { Off, Trace, @@ -141,9 +145,9 @@ export interface ILoggerService { /** * Creates a logger, or gets one if it already exists. * - * This will also register the logger with the logger service unless `donotRegister` is set to `true`. + * This will also register the logger with the logger service. */ - createLogger(resource: URI, options?: ILoggerOptions, donotRegister?: boolean): ILogger; + createLogger(resource: URI, options?: ILoggerOptions): ILogger; /** * Gets an existing logger, if any. @@ -153,7 +157,12 @@ export interface ILoggerService { /** * An event which fires when the log level of a logger has changed */ - readonly onDidChangeLogLevel: Event<[URI, LogLevel]>; + readonly onDidChangeLogLevel: Event; + + /** + * Set default log level. + */ + setLogLevel(level: LogLevel): void; /** * Set log level for a logger. @@ -161,9 +170,9 @@ export interface ILoggerService { setLogLevel(resource: URI, level: LogLevel): void; /** - * Get log level for a logger. + * Get log level for a logger or the default log level. */ - getLogLevel(resource: URI): LogLevel | undefined; + getLogLevel(resource?: URI): LogLevel; /** * An event which fires when the visibility of a logger has changed @@ -459,111 +468,65 @@ export class AdapterLogger extends AbstractLogger implements ILogger { } } -export class MultiplexLogService extends AbstractLogger implements ILogService { - declare readonly _serviceBrand: undefined; +export class MultiplexLogger extends AbstractLogger implements ILogger { - constructor(private readonly logServices: ReadonlyArray) { + constructor(private readonly loggers: ReadonlyArray) { super(); - if (logServices.length) { - this.setLevel(logServices[0].getLevel()); + if (loggers.length) { + this.setLevel(loggers[0].getLevel()); } } override setLevel(level: LogLevel): void { - for (const logService of this.logServices) { - logService.setLevel(level); + for (const logger of this.loggers) { + logger.setLevel(level); } super.setLevel(level); } trace(message: string, ...args: any[]): void { - for (const logService of this.logServices) { - logService.trace(message, ...args); + for (const logger of this.loggers) { + logger.trace(message, ...args); } } debug(message: string, ...args: any[]): void { - for (const logService of this.logServices) { - logService.debug(message, ...args); + for (const logger of this.loggers) { + logger.debug(message, ...args); } } info(message: string, ...args: any[]): void { - for (const logService of this.logServices) { - logService.info(message, ...args); + for (const logger of this.loggers) { + logger.info(message, ...args); } } warn(message: string, ...args: any[]): void { - for (const logService of this.logServices) { - logService.warn(message, ...args); + for (const logger of this.loggers) { + logger.warn(message, ...args); } } error(message: string | Error, ...args: any[]): void { - for (const logService of this.logServices) { - logService.error(message, ...args); + for (const logger of this.loggers) { + logger.error(message, ...args); } } flush(): void { - for (const logService of this.logServices) { - logService.flush(); + for (const logger of this.loggers) { + logger.flush(); } } override dispose(): void { - for (const logService of this.logServices) { - logService.dispose(); + for (const logger of this.loggers) { + logger.dispose(); } } } -export class LogService extends Disposable implements ILogService { - declare readonly _serviceBrand: undefined; - - constructor(private logger: ILogger) { - super(); - this._register(logger); - } - - get onDidChangeLogLevel(): Event { - return this.logger.onDidChangeLogLevel; - } - - setLevel(level: LogLevel): void { - this.logger.setLevel(level); - } - - getLevel(): LogLevel { - return this.logger.getLevel(); - } - - trace(message: string, ...args: any[]): void { - this.logger.trace(message, ...args); - } - - debug(message: string, ...args: any[]): void { - this.logger.debug(message, ...args); - } - - info(message: string, ...args: any[]): void { - this.logger.info(message, ...args); - } - - warn(message: string, ...args: any[]): void { - this.logger.warn(message, ...args); - } - - error(message: string | Error, ...args: any[]): void { - this.logger.error(message, ...args); - } - - flush(): void { - this.logger.flush(); - } -} - export abstract class AbstractLoggerService extends Disposable implements ILoggerService { declare readonly _serviceBrand: undefined; @@ -575,7 +538,7 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge private _onDidChangeLoggers = this._register(new Emitter<{ added: ILoggerResource[]; removed: ILoggerResource[] }>); readonly onDidChangeLoggers = this._onDidChangeLoggers.event; - private _onDidChangeLogLevel = this._register(new Emitter<[URI, LogLevel]>); + private _onDidChangeLogLevel = this._register(new Emitter); readonly onDidChangeLogLevel = this._onDidChangeLogLevel.event; private _onDidChangeVisibility = this._register(new Emitter<[URI, boolean]>); @@ -583,11 +546,9 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge constructor( protected logLevel: LogLevel, - onDidChangeLogLevel: Event, loggerResources?: Iterable, ) { super(); - this._register(onDidChangeLogLevel(logLevel => this.setGlobalLogLevel(logLevel))); if (loggerResources) { for (const loggerResource of loggerResources) { this._loggerResources.set(loggerResource.resource, loggerResource); @@ -612,13 +573,27 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge return logger; } - setLogLevel(resource: URI, logLevel: LogLevel): void { - const loggerResource = this._loggerResources.get(resource); - if (loggerResource && logLevel !== loggerResource.logLevel) { - loggerResource.logLevel = logLevel === this.logLevel ? undefined : logLevel; - this._loggers.get(resource)?.setLevel(logLevel); - this._loggerResources.set(loggerResource.resource, loggerResource); - this._onDidChangeLogLevel.fire([resource, logLevel]); + setLogLevel(logLevel: LogLevel): void; + setLogLevel(resource: URI, logLevel: LogLevel): void; + setLogLevel(arg1: any, arg2?: any): void { + if (URI.isUri(arg1)) { + const resource = arg1; + const logLevel = arg2; + const loggerResource = this._loggerResources.get(resource); + if (loggerResource && logLevel !== loggerResource.logLevel) { + loggerResource.logLevel = logLevel === this.logLevel ? undefined : logLevel; + this._loggers.get(resource)?.setLevel(logLevel); + this._loggerResources.set(loggerResource.resource, loggerResource); + this._onDidChangeLogLevel.fire([resource, logLevel]); + } + } else { + this.logLevel = arg1; + for (const [resource, logger] of this._loggers.entries()) { + if (this._loggerResources.get(resource)?.logLevel === undefined) { + logger.setLevel(this.logLevel); + } + } + this._onDidChangeLogLevel.fire(this.logLevel); } } @@ -631,22 +606,21 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge } } - protected setGlobalLogLevel(logLevel: LogLevel): void { - this.logLevel = logLevel; - for (const [resource, logger] of this._loggers.entries()) { - if (this._loggerResources.get(resource)?.logLevel === undefined) { - logger.setLevel(this.logLevel); - } + getLogLevel(resource?: URI): LogLevel { + let logLevel; + if (resource) { + logLevel = this._loggerResources.get(resource)?.logLevel; } - } - - getLogLevel(resource: URI): LogLevel | undefined { - return this._loggerResources.get(resource)?.logLevel; + return logLevel ?? this.logLevel; } registerLogger(resource: ILoggerResource): void { const existing = this._loggerResources.get(resource.resource); - if (!existing) { + if (existing) { + if (existing.hidden !== resource.hidden) { + this.setVisibility(resource.resource, !resource.hidden); + } + } else { this._loggerResources.set(resource.resource, resource); this._onDidChangeLoggers.fire({ added: [resource], removed: [] }); } @@ -703,7 +677,7 @@ export class NullLogService extends NullLogger implements ILogService { export class NullLoggerService extends AbstractLoggerService { - constructor() { super(LogLevel.Info, Event.None); } + constructor() { super(LogLevel.Info); } protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions | undefined): ILogger { return new NullLogger(); @@ -753,3 +727,11 @@ export function parseLogLevel(logLevel: string): LogLevel | undefined { } return undefined; } + +export function setLogLevel(loggerService: ILoggerService, logLevel: LogLevel | [URI, LogLevel]): void { + if (isLogLevel(logLevel)) { + loggerService.setLogLevel(logLevel); + } else { + loggerService.setLogLevel(logLevel[0], logLevel[1]); + } +} diff --git a/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts index faae44937d4bd..6318120c9fd91 100644 --- a/src/vs/platform/log/common/logIpc.ts +++ b/src/vs/platform/log/common/logIpc.ts @@ -3,63 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Event } from 'vs/base/common/event'; import { URI, UriDto } from 'vs/base/common/uri'; +import { Event } from 'vs/base/common/event'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { AbstractLoggerService, AbstractMessageLogger, AdapterLogger, DidChangeLoggersEvent, ILogger, ILoggerOptions, ILoggerResource, ILoggerService, ILogService, LogLevel, LogService } from 'vs/platform/log/common/log'; - -export class LogLevelChannel implements IServerChannel { - - onDidChangeLogLevel: Event; - - constructor( - private readonly logService: ILogService, - private readonly loggerService: ILoggerService - ) { - this.onDidChangeLogLevel = Event.buffer(logService.onDidChangeLogLevel, true); - } - - listen(_: unknown, event: string): Event { - switch (event) { - case 'onDidChangeLogLevel': return this.onDidChangeLogLevel; - } - - throw new Error(`Event not found: ${event}`); - } - - async call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'setLevel': return arg[1] ? this.loggerService.setLogLevel(URI.revive(arg[1]), arg[0]) : this.logService.setLevel(arg[0]); - } - - throw new Error(`Call not found: ${command}`); - } - -} - -export class LogLevelChannelClient { - - constructor(private channel: IChannel) { } - - get onDidChangeLogLevel(): Event { - return this.channel.listen('onDidChangeLogLevel'); - } - - setLevel(level: LogLevel, resource?: URI): void { - LogLevelChannelClient.setLevel(this.channel, level, resource); - } - - public static setLevel(channel: IChannel, level: LogLevel, resource?: URI): Promise { - return channel.call('setLevel', [level, resource]); - } - -} +import { AbstractLoggerService, AbstractMessageLogger, AdapterLogger, DidChangeLoggersEvent, ILogger, ILoggerOptions, ILoggerResource, ILoggerService, isLogLevel, LogLevel } from 'vs/platform/log/common/log'; +import { Disposable } from 'vs/base/common/lifecycle'; export class LoggerChannelClient extends AbstractLoggerService implements ILoggerService { - constructor(private readonly windowId: number | undefined, logLevel: LogLevel, onDidChangeLogLevel: Event, loggers: UriDto[], private readonly channel: IChannel) { - super(logLevel, onDidChangeLogLevel, loggers.map(loggerResource => ({ ...loggerResource, resource: URI.revive(loggerResource.resource) }))); - this._register(channel.listen<[URI, LogLevel]>('onDidChangeLogLevel', windowId)(([resource, logLevel]) => super.setLogLevel(URI.revive(resource), logLevel))); + constructor(private readonly windowId: number | undefined, logLevel: LogLevel, loggers: UriDto[], private readonly channel: IChannel) { + super(logLevel, loggers.map(loggerResource => ({ ...loggerResource, resource: URI.revive(loggerResource.resource), hidden: loggerResource.hidden || !!loggerResource.extensionId }))); + this._register(channel.listen('onDidChangeLogLevel', windowId)(arg => { + if (isLogLevel(arg)) { + super.setLogLevel(arg); + } else { + super.setLogLevel(URI.revive(arg[0]), arg[1]); + } + })); this._register(channel.listen<[URI, boolean]>('onDidChangeVisibility', windowId)(([resource, visibility]) => super.setVisibility(URI.revive(resource), visibility))); this._register(channel.listen('onDidChangeLoggers', windowId)(({ added, removed }) => { for (const loggerResource of added) { @@ -89,9 +49,11 @@ export class LoggerChannelClient extends AbstractLoggerService implements ILogge this.channel.call('deregisterLogger', [resource, this.windowId]); } - override setLogLevel(resource: URI, logLevel: LogLevel): void { - super.setLogLevel(resource, logLevel); - this.channel.call('setLogLevel', [resource, logLevel]); + override setLogLevel(logLevel: LogLevel): void; + override setLogLevel(resource: URI, logLevel: LogLevel): void; + override setLogLevel(arg1: any, arg2?: any): void { + super.setLogLevel(arg1, arg2); + this.channel.call('setLogLevel', [arg1, arg2]); } override setVisibility(resource: URI, visibility: boolean): void { @@ -103,6 +65,12 @@ export class LoggerChannelClient extends AbstractLoggerService implements ILogge return new Logger(this.channel, file, logLevel, options); } + public static setLogLevel(channel: IChannel, level: LogLevel): Promise; + public static setLogLevel(channel: IChannel, resource: URI, level: LogLevel): Promise; + public static setLogLevel(channel: IChannel, arg1: any, arg2?: any): Promise { + return channel.call('setLogLevel', [arg1, arg2]); + } + } class Logger extends AbstractMessageLogger { @@ -139,16 +107,54 @@ class Logger extends AbstractMessageLogger { } } -export class FollowerLogService extends LogService implements ILogService { +export class LoggerChannel implements IServerChannel { - constructor(private parent: LogLevelChannelClient, logService: ILogService) { - super(logService); - this._register(parent.onDidChangeLogLevel(level => logService.setLevel(level))); + constructor(private readonly loggerService: ILoggerService) { } + + listen(_: unknown, event: string, windowId?: number): Event { + switch (event) { + case 'onDidChangeLoggers': return this.loggerService.onDidChangeLoggers; + case 'onDidChangeVisibility': return this.loggerService.onDidChangeVisibility; + case 'onDidChangeLogLevel': return this.loggerService.onDidChangeLogLevel; + } + throw new Error(`Event not found: ${event}`); } - override setLevel(level: LogLevel): void { - super.setLevel(level); + async call(_: unknown, command: string, arg?: any): Promise { + switch (command) { + case 'setLogLevel': return isLogLevel(arg[0]) ? this.loggerService.setLogLevel(arg[0]) : this.loggerService.setLogLevel(URI.revive(arg[0]), arg[1]); + case 'getRegisteredLoggers': return Promise.resolve([...this.loggerService.getRegisteredLoggers()]); + } + + throw new Error(`Call not found: ${command}`); + } + +} + +export class RemoteLoggerChannelClient extends Disposable { + + constructor(loggerService: ILoggerService, channel: IChannel) { + super(); + + channel.call('setLogLevel', [loggerService.getLogLevel()]); + this._register(loggerService.onDidChangeLogLevel(arg => channel.call('setLogLevel', [arg]))); + + channel.call('getRegisteredLoggers').then(loggers => { + for (const loggerResource of loggers) { + loggerService.registerLogger({ ...loggerResource, resource: URI.revive(loggerResource.resource) }); + } + }); + + this._register(channel.listen<[URI, boolean]>('onDidChangeVisibility')(([resource, visibility]) => loggerService.setVisibility(URI.revive(resource), visibility))); + + this._register(channel.listen('onDidChangeLoggers')(({ added, removed }) => { + for (const loggerResource of added) { + loggerService.registerLogger({ ...loggerResource, resource: URI.revive(loggerResource.resource) }); + } + for (const loggerResource of removed) { + loggerService.deregisterLogger(loggerResource.resource); + } + })); - this.parent.setLevel(level); } } diff --git a/src/vs/platform/log/common/logService.ts b/src/vs/platform/log/common/logService.ts new file mode 100644 index 0000000000000..095d8b931e3e2 --- /dev/null +++ b/src/vs/platform/log/common/logService.ts @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { Event } from 'vs/base/common/event'; +import { ILogger, ILogService, LogLevel, MultiplexLogger } from 'vs/platform/log/common/log'; + +export class LogService extends Disposable implements ILogService { + + declare readonly _serviceBrand: undefined; + + private readonly logger: ILogger; + + constructor(primaryLogger: ILogger, otherLoggers: ILogger[] = []) { + super(); + this.logger = new MultiplexLogger([primaryLogger, ...otherLoggers]); + this._register(primaryLogger.onDidChangeLogLevel(level => this.setLevel(level))); + } + + get onDidChangeLogLevel(): Event { + return this.logger.onDidChangeLogLevel; + } + + setLevel(level: LogLevel): void { + this.logger.setLevel(level); + } + + getLevel(): LogLevel { + return this.logger.getLevel(); + } + + trace(message: string, ...args: any[]): void { + this.logger.trace(message, ...args); + } + + debug(message: string, ...args: any[]): void { + this.logger.debug(message, ...args); + } + + info(message: string, ...args: any[]): void { + this.logger.info(message, ...args); + } + + warn(message: string, ...args: any[]): void { + this.logger.warn(message, ...args); + } + + error(message: string | Error, ...args: any[]): void { + this.logger.error(message, ...args); + } + + flush(): void { + this.logger.flush(); + } +} diff --git a/src/vs/platform/log/electron-main/logIpc.ts b/src/vs/platform/log/electron-main/logIpc.ts index 0ecbe74cfadff..c2da89d1ee7d9 100644 --- a/src/vs/platform/log/electron-main/logIpc.ts +++ b/src/vs/platform/log/electron-main/logIpc.ts @@ -26,7 +26,7 @@ export class LoggerChannel implements IServerChannel { async call(_: unknown, command: string, arg?: any): Promise { switch (command) { - case 'createLogger': this.createLogger(URI.revive(arg[0]), arg[1], arg[2]); return; + case 'createLogger': this.createLogger(URI.revive(arg[0]), arg[1]); return; case 'log': return this.log(URI.revive(arg[0]), arg[1]); case 'consoleLog': return this.consoleLog(arg[0], arg[1]); case 'setLogLevel': return this.loggerService.setLogLevel(URI.revive(arg[0]), arg[1]); @@ -38,8 +38,8 @@ export class LoggerChannel implements IServerChannel { throw new Error(`Call not found: ${command}`); } - private createLogger(file: URI, options: ILoggerOptions, donotRegister?: boolean): void { - this.loggers.set(file.toString(), this.loggerService.createLogger(file, options, donotRegister)); + private createLogger(file: URI, options: ILoggerOptions): void { + this.loggers.set(file.toString(), this.loggerService.createLogger(file, options)); } private consoleLog(level: LogLevel, args: any[]): void { diff --git a/src/vs/platform/log/electron-main/loggerService.ts b/src/vs/platform/log/electron-main/loggerService.ts index cb278773fb405..67029bacdfa76 100644 --- a/src/vs/platform/log/electron-main/loggerService.ts +++ b/src/vs/platform/log/electron-main/loggerService.ts @@ -7,14 +7,14 @@ import { ResourceMap } from 'vs/base/common/map'; import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { DidChangeLoggersEvent, ILoggerResource, ILoggerService, LogLevel } from 'vs/platform/log/common/log'; +import { DidChangeLoggersEvent, ILoggerResource, ILoggerService, LogLevel, isLogLevel } from 'vs/platform/log/common/log'; import { LoggerService } from 'vs/platform/log/node/loggerService'; export const ILoggerMainService = refineServiceDecorator(ILoggerService); export interface ILoggerMainService extends ILoggerService { - getOnDidChangeLogLevelEvent(windowId: number): Event<[URI, LogLevel]>; + getOnDidChangeLogLevelEvent(windowId: number): Event; getOnDidChangeVisibilityEvent(windowId: number): Event<[URI, boolean]>; @@ -54,8 +54,8 @@ export class LoggerMainService extends LoggerService implements ILoggerMainServi return resources; } - getOnDidChangeLogLevelEvent(windowId: number): Event<[URI, LogLevel]> { - return Event.filter(this.onDidChangeLogLevel, ([resource]) => this.isInterestedLoggerResource(resource, windowId)); + getOnDidChangeLogLevelEvent(windowId: number): Event { + return Event.filter(this.onDidChangeLogLevel, arg => isLogLevel(arg) || this.isInterestedLoggerResource(arg[0], windowId)); } getOnDidChangeVisibilityEvent(windowId: number): Event<[URI, boolean]> { diff --git a/src/vs/platform/log/node/loggerService.ts b/src/vs/platform/log/node/loggerService.ts index 9e1c2e7258148..d9bd4bc1269c2 100644 --- a/src/vs/platform/log/node/loggerService.ts +++ b/src/vs/platform/log/node/loggerService.ts @@ -5,19 +5,12 @@ import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; -import { AbstractLoggerService, ILogger, ILoggerOptions, ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log'; +import { AbstractLoggerService, ILogger, ILoggerOptions, ILoggerService, LogLevel } from 'vs/platform/log/common/log'; import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; export class LoggerService extends AbstractLoggerService implements ILoggerService { - constructor( - @ILogService logService: ILogService - ) { - super(logService.getLevel(), logService.onDidChangeLogLevel); - } - protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger { return new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, !!options?.donotUseFormatters, logLevel); } } - diff --git a/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts b/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts index 2d189bb48c86c..55d65519cfba9 100644 --- a/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts +++ b/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts @@ -76,7 +76,7 @@ export class TestTelemetryLoggerService implements ILoggerService { onDidChangeLogLevel = Event.None; onDidChangeLoggers = Event.None; setLogLevel(): void { } - getLogLevel() { return undefined; } + getLogLevel() { return LogLevel.Info; } setVisibility(): void { } getDefaultLogLevel() { return this.logLevel; } registerLogger() { } diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 07ba6ce1609c0..7a906c6bd35bc 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -209,7 +209,7 @@ export enum TerminalIpcChannels { /** * Deals with logging from the pty host process. */ - Log = 'log', + Logger = 'logger', /** * Enables the detection of unresponsive pty hosts. */ diff --git a/src/vs/platform/terminal/node/ptyHostMain.ts b/src/vs/platform/terminal/node/ptyHostMain.ts index da8071c9084de..19fc0c0d66ced 100644 --- a/src/vs/platform/terminal/node/ptyHostMain.ts +++ b/src/vs/platform/terminal/node/ptyHostMain.ts @@ -7,11 +7,12 @@ import { join } from 'vs/base/common/path'; import { URI } from 'vs/base/common/uri'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { Server } from 'vs/base/parts/ipc/node/ipc.cp'; +import { localize } from 'vs/nls'; import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { BufferLogService } from 'vs/platform/log/common/bufferLog'; -import { ConsoleLogger, LogService, MultiplexLogService } from 'vs/platform/log/common/log'; -import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; +import { ConsoleLogger, LogLevel } from 'vs/platform/log/common/log'; +import { LoggerChannel } from 'vs/platform/log/common/logIpc'; +import { LogService } from 'vs/platform/log/common/logService'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -24,18 +25,15 @@ const server = new Server('ptyHost'); const lastPtyId = parseInt(process.env.VSCODE_LAST_PTY_ID || '0'); delete process.env.VSCODE_LAST_PTY_ID; -// Logging const productService: IProductService = { _serviceBrand: undefined, ...product }; const environmentService = new NativeEnvironmentService(parseArgs(process.argv, OPTIONS), productService); -const bufferLogService = new BufferLogService(); -const logService = new LogService(new MultiplexLogService([ - new ConsoleLogger(), - bufferLogService -])); -const loggerService = new LoggerService(logService); -bufferLogService.logger = loggerService.createLogger(URI.file(join(environmentService.logsPath, `${TerminalLogConstants.FileName}.log`)), { name: TerminalLogConstants.FileName }); -const logLevelChannel = new LogLevelChannel(logService, loggerService); -server.registerChannel(TerminalIpcChannels.Log, logLevelChannel); + +// Logging +const loggerService = new LoggerService(LogLevel.Info); +server.registerChannel(TerminalIpcChannels.Logger, new LoggerChannel(loggerService)); +const logger = loggerService.createLogger(URI.file(join(environmentService.logsPath, `${TerminalLogConstants.FileName}.log`)), { name: process.env.VSCODE_PTY_LOG_NAME ?? localize('ptyHost', "Pty Host") }); +delete process.env.VSCODE_PTY_LOG_NAME; +const logService = new LogService(logger, [new ConsoleLogger()]); const heartbeatService = new HeartbeatService(); server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService)); diff --git a/src/vs/platform/terminal/node/ptyHostService.ts b/src/vs/platform/terminal/node/ptyHostService.ts index ac9da2324a715..ee5790c59ccff 100644 --- a/src/vs/platform/terminal/node/ptyHostService.ts +++ b/src/vs/platform/terminal/node/ptyHostService.ts @@ -14,17 +14,13 @@ import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/envi import { parsePtyHostPort } from 'vs/platform/environment/common/environmentService'; import { getResolvedShellEnv } from 'vs/platform/shell/node/shellEnv'; import { ILogService, ILoggerService } from 'vs/platform/log/common/log'; -import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; import { RequestStore } from 'vs/platform/terminal/common/requestStore'; -import { HeartbeatConstants, IHeartbeatService, IProcessDataEvent, IPtyService, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalLaunchError, ITerminalProfile, ITerminalsLayoutInfo, TerminalIcon, TerminalIpcChannels, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, TerminalSettingId, ISerializedTerminalState, ITerminalProcessOptions, TerminalLogConstants } from 'vs/platform/terminal/common/terminal'; +import { HeartbeatConstants, IHeartbeatService, IProcessDataEvent, IPtyService, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalLaunchError, ITerminalProfile, ITerminalsLayoutInfo, TerminalIcon, TerminalIpcChannels, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, TerminalSettingId, ISerializedTerminalState, ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal'; import { registerTerminalPlatformConfiguration } from 'vs/platform/terminal/common/terminalPlatformConfiguration'; import { IGetTerminalLayoutInfoArgs, IProcessDetails, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; import { detectAvailableProfiles } from 'vs/platform/terminal/node/terminalProfiles'; import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/capabilities/capabilities'; -import { localize } from 'vs/nls'; -import { URI } from 'vs/base/common/uri'; -import { join } from 'vs/base/common/path'; -import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { RemoteLoggerChannelClient } from 'vs/platform/log/common/logIpc'; enum Constants { MaxRestarts = 5 @@ -83,11 +79,11 @@ export class PtyHostService extends Disposable implements IPtyService { constructor( private readonly _reconnectConstants: IReconnectConstants, + private readonly loggerName: string, @IConfigurationService private readonly _configurationService: IConfigurationService, @IEnvironmentService private readonly _environmentService: INativeEnvironmentService, @ILogService private readonly _logService: ILogService, @ILoggerService private readonly _loggerService: ILoggerService, - @IUriIdentityService private readonly _uriIdentityService: IUriIdentityService, ) { super(); @@ -143,6 +139,7 @@ export class PtyHostService extends Disposable implements IPtyService { args: ['--type=ptyHost', '--logsPath', this._environmentService.logsPath], env: { VSCODE_LAST_PTY_ID: lastPtyId, + VSCODE_PTY_LOG_NAME: this.loggerName, VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', VSCODE_PIPE_LOGGING: 'true', VSCODE_VERBOSE_LOGGING: 'true', // transmit console logs from server to client, @@ -184,18 +181,7 @@ export class PtyHostService extends Disposable implements IPtyService { })); // Setup logging - const logChannel = client.getChannel(TerminalIpcChannels.Log); - LogLevelChannelClient.setLevel(logChannel, this._logService.getLevel()); - const ptyHostLogResource = URI.file(join(this._environmentService.logsPath, `${TerminalLogConstants.FileName}.log`)); - this._loggerService.registerLogger({ id: 'ptyHostLog', name: localize('ptyHost', "Pty Host"), resource: ptyHostLogResource }); - this._register(this._logService.onDidChangeLogLevel(() => { - LogLevelChannelClient.setLevel(logChannel, this._logService.getLevel()); - })); - this._register(this._loggerService.onDidChangeLogLevel(([resource, logLevel]) => { - if (this._uriIdentityService.extUri.isEqual(ptyHostLogResource, resource)) { - LogLevelChannelClient.setLevel(logChannel, logLevel); - } - })); + this._register(new RemoteLoggerChannelClient(this._loggerService, client.getChannel(TerminalIpcChannels.Logger))); // Create proxy and forward events const proxy = ProxyChannel.toService(client.getChannel(TerminalIpcChannels.PtyHost)); diff --git a/src/vs/platform/terminal/test/common/requestStore.test.ts b/src/vs/platform/terminal/test/common/requestStore.test.ts index dedb41c066924..13ff93b70760c 100644 --- a/src/vs/platform/terminal/test/common/requestStore.test.ts +++ b/src/vs/platform/terminal/test/common/requestStore.test.ts @@ -5,7 +5,8 @@ import { fail, strictEqual } from 'assert'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { ConsoleLogger, ILogService, LogService } from 'vs/platform/log/common/log'; +import { ConsoleLogger, ILogService } from 'vs/platform/log/common/log'; +import { LogService } from 'vs/platform/log/common/logService'; import { RequestStore } from 'vs/platform/terminal/common/requestStore'; suite('RequestStore', () => { diff --git a/src/vs/server/node/remoteExtensionHostAgentCli.ts b/src/vs/server/node/remoteExtensionHostAgentCli.ts index 5d975c695c8a8..8c35f399e3e8f 100644 --- a/src/vs/server/node/remoteExtensionHostAgentCli.ts +++ b/src/vs/server/node/remoteExtensionHostAgentCli.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { getLogLevel, ILogService, LogService } from 'vs/platform/log/common/log'; +import { getLogLevel, ILogService } from 'vs/platform/log/common/log'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ConfigurationService } from 'vs/platform/configuration/common/configurationService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -48,6 +48,7 @@ import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagemen import { NullPolicyService } from 'vs/platform/policy/common/policy'; import { ServerUserDataProfilesService } from 'vs/platform/userDataProfile/node/userDataProfile'; import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/node/extensionsProfileScannerService'; +import { LogService } from 'vs/platform/log/common/logService'; class CliMain extends Disposable { @@ -84,7 +85,7 @@ class CliMain extends Disposable { const environmentService = new ServerEnvironmentService(this.args, productService); services.set(IServerEnvironmentService, environmentService); - const logService: ILogService = new LogService(new SpdLogLogger(RemoteExtensionLogFileName, join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), true, false, getLogLevel(environmentService))); + const logService = new LogService(new SpdLogLogger(RemoteExtensionLogFileName, join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), true, false, getLogLevel(environmentService))); services.set(ILogService, logService); logService.trace(`Remote configuration data at ${this.remoteDataFolder}`); logService.trace('process arguments:', this.args); diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 2b35b1ea28f66..e428f93057bdf 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -38,8 +38,7 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { NativeLanguagePackService } from 'vs/platform/languagePacks/node/languagePacks'; -import { AbstractLogger, DEFAULT_LOG_LEVEL, getLogLevel, ILoggerService, ILogService, LogLevel, MultiplexLogService } from 'vs/platform/log/common/log'; -import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; +import { AbstractLogger, DEFAULT_LOG_LEVEL, getLogLevel, ILoggerService, ILogService, LogLevel } from 'vs/platform/log/common/log'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; @@ -75,9 +74,11 @@ import { NullPolicyService } from 'vs/platform/policy/common/policy'; import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import { URI } from 'vs/base/common/uri'; -import { BufferLogService } from 'vs/platform/log/common/bufferLog'; import { ServerUserDataProfilesService } from 'vs/platform/userDataProfile/node/userDataProfile'; import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement/node/extensionsProfileScannerService'; +import { LogService } from 'vs/platform/log/common/logService'; +import { LoggerChannel } from 'vs/platform/log/common/logIpc'; +import { localize } from 'vs/nls'; const eventPrefix = 'monacoworkbench'; @@ -92,15 +93,14 @@ export async function setupServerServices(connectionToken: ServerConnectionToken services.set(IEnvironmentService, environmentService); services.set(INativeEnvironmentService, environmentService); - const bufferLogService = new BufferLogService(); - const logService = new MultiplexLogService([new ServerLogService(getLogLevel(environmentService)), bufferLogService]); - services.set(ILogService, logService); - setTimeout(() => cleanupOlderLogs(environmentService.logsPath).then(null, err => logService.error(err)), 10000); - - const loggerService = new LoggerService(logService); + const loggerService = new LoggerService(getLogLevel(environmentService)); services.set(ILoggerService, loggerService); + socketServer.registerChannel('logger', new LoggerChannel(loggerService)); - bufferLogService.logger = loggerService.createLogger(URI.file(path.join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`)), { name: RemoteExtensionLogFileName }); + const logger = loggerService.createLogger(URI.file(path.join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`)), { id: 'remoteServerLog', name: localize('remoteExtensionLog', "Remote Server") }); + const logService = new LogService(logger, [new ServerLogger(getLogLevel(environmentService))]); + services.set(ILogService, logService); + setTimeout(() => cleanupOlderLogs(environmentService.logsPath).then(null, err => logService.error(err)), 10000); logService.trace(`Remote configuration data at ${REMOTE_DATA_FOLDER}`); logService.trace('process arguments:', environmentService.args); @@ -113,7 +113,6 @@ export async function setupServerServices(connectionToken: ServerConnectionToken // TODO: @Sandy @Joao need dynamic context based router const router = new StaticRouter(ctx => ctx.clientId === 'renderer'); - socketServer.registerChannel('logger', new LogLevelChannel(logService, loggerService)); // Files const fileService = disposables.add(new FileService(logService)); @@ -189,7 +188,8 @@ export async function setupServerServices(connectionToken: ServerConnectionToken graceTime: ProtocolConstants.ReconnectionGraceTime, shortGraceTime: ProtocolConstants.ReconnectionShortGraceTime, scrollback: configurationService.getValue(TerminalSettingId.PersistentSessionScrollback) ?? 100 - } + }, + localize('ptyHost', "Remote Pty Host") ); services.set(IPtyService, ptyService); @@ -259,8 +259,7 @@ export class SocketServer extends IPCServer { } } -class ServerLogService extends AbstractLogger implements ILogService { - _serviceBrand: undefined; +class ServerLogger extends AbstractLogger { private useColors: boolean; constructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL) { diff --git a/src/vs/workbench/api/browser/mainThreadLogService.ts b/src/vs/workbench/api/browser/mainThreadLogService.ts index 62e751bd36719..bff61be1ddf2e 100644 --- a/src/vs/workbench/api/browser/mainThreadLogService.ts +++ b/src/vs/workbench/api/browser/mainThreadLogService.ts @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; -import { ILoggerOptions, ILoggerService, ILogService, log, LogLevel, LogLevelToString, parseLogLevel } from 'vs/platform/log/common/log'; +import { ILoggerOptions, ILoggerResource, ILoggerService, ILogService, isLogLevel, log, LogLevel, LogLevelToString, parseLogLevel } from 'vs/platform/log/common/log'; 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 { UriComponents, URI, UriDto } 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 { IOutputService } from 'vs/workbench/services/output/common/output'; @extHostNamedCustomer(MainContext.MainThreadLogger) export class MainThreadLoggerService implements MainThreadLoggerShape { @@ -20,13 +19,16 @@ export class MainThreadLoggerService implements MainThreadLoggerShape { constructor( extHostContext: IExtHostContext, - @ILogService logService: ILogService, @ILoggerService private readonly loggerService: ILoggerService, - @IOutputService outputService: IOutputService, ) { const proxy = extHostContext.getProxy(ExtHostContext.ExtHostLogLevelServiceShape); - this.disposables.add(logService.onDidChangeLogLevel(level => proxy.$setLevel(level))); - this.disposables.add(loggerService.onDidChangeLogLevel(([resource, logLevel]) => proxy.$setLevel(logLevel, resource))); + this.disposables.add(loggerService.onDidChangeLogLevel(arg => { + if (isLogLevel(arg)) { + proxy.$setLogLevel(arg); + } else { + proxy.$setLogLevel(arg[1], arg[0]); + } + })); } $log(file: UriComponents, messages: [LogLevel, string][]): void { @@ -40,7 +42,18 @@ export class MainThreadLoggerService implements MainThreadLoggerShape { } async $createLogger(file: UriComponents, options?: ILoggerOptions): Promise { - this.loggerService.createLogger(URI.revive(file), options, true /* do not register the loggers from the extension host */); + this.loggerService.createLogger(URI.revive(file), options); + } + + async $registerLogger(logResource: UriDto): Promise { + this.loggerService.registerLogger({ + ...logResource, + resource: URI.revive(logResource.resource) + }); + } + + async $deregisterLogger(resource: UriComponents): Promise { + this.loggerService.deregisterLogger(URI.revive(resource)); } dispose(): void { @@ -51,13 +64,13 @@ export class MainThreadLoggerService implements MainThreadLoggerShape { // --- Internal commands to improve extension test runs CommandsRegistry.registerCommand('_extensionTests.setLogLevel', function (accessor: ServicesAccessor, level: string) { - const logService = accessor.get(ILogService); + const loggerService = accessor.get(ILoggerService); const environmentService = accessor.get(IEnvironmentService); if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) { const logLevel = parseLogLevel(level); if (logLevel !== undefined) { - logService.setLevel(logLevel); + loggerService.setLogLevel(logLevel); } } }); diff --git a/src/vs/workbench/api/browser/mainThreadOutputService.ts b/src/vs/workbench/api/browser/mainThreadOutputService.ts index 4a22af48b46a0..4f5c2c9a98427 100644 --- a/src/vs/workbench/api/browser/mainThreadOutputService.ts +++ b/src/vs/workbench/api/browser/mainThreadOutputService.ts @@ -12,7 +12,6 @@ import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { IViewsService } from 'vs/workbench/common/views'; import { isNumber } from 'vs/base/common/types'; -import { ILoggerService } from 'vs/platform/log/common/log'; @extHostNamedCustomer(MainContext.MainThreadOutputService) export class MainThreadOutputService extends Disposable implements MainThreadOutputServiceShape { @@ -22,18 +21,15 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut private readonly _proxy: ExtHostOutputServiceShape; private readonly _outputService: IOutputService; private readonly _viewsService: IViewsService; - private readonly _loggerService: ILoggerService; constructor( extHostContext: IExtHostContext, @IOutputService outputService: IOutputService, @IViewsService viewsService: IViewsService, - @ILoggerService loggerService: ILoggerService, ) { super(); this._outputService = outputService; this._viewsService = viewsService; - this._loggerService = loggerService; this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostOutputService); @@ -45,17 +41,13 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut setVisibleChannel(); } - public async $register(label: string, file: UriComponents, log: boolean, languageId: string | undefined, extensionId: string): Promise { + public async $register(label: string, file: UriComponents, languageId: string | undefined, extensionId: string): Promise { const idCounter = (MainThreadOutputService._extensionIdPool.get(extensionId) || 0) + 1; MainThreadOutputService._extensionIdPool.set(extensionId, idCounter); const id = `extension-output-${extensionId}-#${idCounter}-${label}`; const resource = URI.revive(file); - if (log) { - this._loggerService.registerLogger({ resource, id, name: label, extensionId }); - } else { - Registry.as(Extensions.OutputChannels).registerChannel({ id, label, file: resource, log, languageId, extensionId }); - } + Registry.as(Extensions.OutputChannels).registerChannel({ id, label, file: resource, log: false, languageId, extensionId }); this._register(toDisposable(() => this.$dispose(id))); return id; } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 9860d5662b2f3..d71fcc8e9fc28 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -32,7 +32,7 @@ import { IExtensionIdWithVersion } from 'vs/platform/extensionManagement/common/ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import * as files from 'vs/platform/files/common/files'; import { ResourceLabelFormatter } from 'vs/platform/label/common/label'; -import { ILoggerOptions, LogLevel } from 'vs/platform/log/common/log'; +import { ILoggerOptions, ILoggerResource, LogLevel } from 'vs/platform/log/common/log'; import { IMarkerData } from 'vs/platform/markers/common/markers'; import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress'; import * as quickInput from 'vs/platform/quickinput/common/quickInput'; @@ -427,7 +427,7 @@ export interface MainThreadMessageServiceShape extends IDisposable { } export interface MainThreadOutputServiceShape extends IDisposable { - $register(label: string, file: UriComponents, log: boolean, languageId: string | undefined, extensionId: string): Promise; + $register(label: string, file: UriComponents, languageId: string | undefined, extensionId: string): Promise; $update(channelId: string, mode: OutputChannelUpdateMode, till?: number): Promise; $reveal(channelId: string, preserveFocus: boolean): Promise; $close(channelId: string): Promise; @@ -1988,12 +1988,14 @@ export interface ExtHostWindowShape { } export interface ExtHostLogLevelServiceShape { - $setLevel(level: LogLevel, resource?: UriComponents): void; + $setLogLevel(level: LogLevel, resource?: UriComponents): void; } export interface MainThreadLoggerShape { $log(file: UriComponents, messages: [LogLevel, string][]): void; $createLogger(file: UriComponents, options?: ILoggerOptions): Promise; + $registerLogger(logger: UriDto): Promise; + $deregisterLogger(resource: UriComponents): Promise; } export interface ExtHostOutputServiceShape { diff --git a/src/vs/workbench/api/common/extHostLogService.ts b/src/vs/workbench/api/common/extHostLogService.ts index e369d85eecf67..f66e88767358c 100644 --- a/src/vs/workbench/api/common/extHostLogService.ts +++ b/src/vs/workbench/api/common/extHostLogService.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ILoggerService, LogService } from 'vs/platform/log/common/log'; +import { ILoggerService } from 'vs/platform/log/common/log'; +import { LogService } from 'vs/platform/log/common/logService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; -import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions'; export class ExtHostLogService extends LogService { @@ -15,7 +15,7 @@ export class ExtHostLogService extends LogService { @ILoggerService loggerService: ILoggerService, @IExtHostInitDataService initData: IExtHostInitDataService, ) { - super(loggerService.createLogger(initData.logFile, { name: ExtensionHostLogFileName })); + super(loggerService.createLogger(initData.logFile, { name: initData.logName })); } } diff --git a/src/vs/workbench/api/common/extHostLoggerService.ts b/src/vs/workbench/api/common/extHostLoggerService.ts index 0dc879e894c9a..90e1df416dc4b 100644 --- a/src/vs/workbench/api/common/extHostLoggerService.ts +++ b/src/vs/workbench/api/common/extHostLoggerService.ts @@ -8,28 +8,26 @@ import { MainThreadLoggerShape, MainContext, ExtHostLogLevelServiceShape as ExtH import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { Event } from 'vs/base/common/event'; -import { isUndefined } from 'vs/base/common/types'; import { revive } from 'vs/base/common/marshalling'; export class ExtHostLoggerService extends AbstractLoggerService implements ExtHostLogLevelServiceShape { declare readonly _serviceBrand: undefined; - private readonly _proxy: MainThreadLoggerShape; + protected readonly _proxy: MainThreadLoggerShape; constructor( @IExtHostRpcService rpc: IExtHostRpcService, @IExtHostInitDataService initData: IExtHostInitDataService, ) { - super(initData.logLevel, Event.None, initData.loggers.map(logger => revive(logger))); + super(initData.logLevel, initData.loggers.map(logger => revive(logger))); this._proxy = rpc.getProxy(MainContext.MainThreadLogger); } - $setLevel(level: LogLevel, resource?: UriComponents): void { + $setLogLevel(logLevel: LogLevel, resource?: UriComponents): void { if (resource) { - this.setLogLevel(URI.revive(resource), level); - } else if (!isUndefined(level)) { - this.setGlobalLogLevel(level); + this.setLogLevel(URI.revive(resource), logLevel); + } else { + this.setLogLevel(logLevel); } } diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index f11f11777c3f7..b632fe47b9cb5 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -167,16 +167,16 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { } const outputDir = await this.outputDirectoryPromise; const file = this.extHostFileSystemInfo.extUri.joinPath(outputDir, `${this.namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`); - const logger = this.loggerService.createLogger(file, { logLevel: 'always', donotRotate: true, donotUseFormatters: true }); - const id = await this.proxy.$register(name, file, false, languageId, extension.identifier.value); + const logger = this.loggerService.createLogger(file, { logLevel: 'always', donotRotate: true, donotUseFormatters: true, hidden: true }); + const id = await this.proxy.$register(name, file, languageId, extension.identifier.value); return new ExtHostOutputChannel(id, name, logger, this.proxy, extension); } private async doCreateLogOutputChannel(name: string, logLevel: LogLevel | undefined, extension: IExtensionDescription): Promise { const extensionLogDir = await this.createExtensionLogDirectory(extension); const file = this.extHostFileSystemInfo.extUri.joinPath(extensionLogDir, `${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`); - const logger = this.loggerService.createLogger(file, { name, logLevel }); - const id = await this.proxy.$register(name, file, true, undefined, extension.identifier.value); + const id = file.toString(); + const logger = this.loggerService.createLogger(file, { id, name, logLevel, extensionId: extension.identifier.value }); return new ExtHostLogOutputChannel(id, name, logger, this.proxy, extension); } diff --git a/src/vs/workbench/api/common/extHostTelemetry.ts b/src/vs/workbench/api/common/extHostTelemetry.ts index cfe7fa5aca487..2209e7ba2f5f9 100644 --- a/src/vs/workbench/api/common/extHostTelemetry.ts +++ b/src/vs/workbench/api/common/extHostTelemetry.ts @@ -35,7 +35,7 @@ export class ExtHostTelemetry implements ExtHostTelemetryShape { @IExtHostInitDataService private readonly initData: IExtHostInitDataService, @ILoggerService loggerService: ILoggerService, ) { - this._outputLogger = loggerService.createLogger(URI.revive(this.initData.environment.extensionTelemetryLogResource)); + this._outputLogger = loggerService.createLogger(URI.revive(this.initData.environment.extensionTelemetryLogResource), { hidden: true }); this._outputLogger.info('Below are logs for extension telemetry events sent to the telemetry output channel API once the log level is set to trace.'); this._outputLogger.info('==========================================================='); } diff --git a/src/vs/workbench/api/node/extHostLoggerService.ts b/src/vs/workbench/api/node/extHostLoggerService.ts index d25dd87516946..37bd422fbbebc 100644 --- a/src/vs/workbench/api/node/extHostLoggerService.ts +++ b/src/vs/workbench/api/node/extHostLoggerService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ILogger, ILoggerOptions, LogLevel } from 'vs/platform/log/common/log'; +import { ILogger, ILoggerOptions, ILoggerResource, LogLevel } from 'vs/platform/log/common/log'; import { URI } from 'vs/base/common/uri'; import { ExtHostLoggerService as BaseExtHostLoggerService } from 'vs/workbench/api/common/extHostLoggerService'; import { Schemas } from 'vs/base/common/network'; @@ -20,4 +20,14 @@ export class ExtHostLoggerService extends BaseExtHostLoggerService { return super.doCreateLogger(resource, logLevel, options); } + override registerLogger(resource: ILoggerResource): void { + super.registerLogger(resource); + this._proxy.$registerLogger(resource); + } + + override deregisterLogger(resource: URI): void { + super.deregisterLogger(resource); + this._proxy.$deregisterLogger(resource); + } + } diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 9d6f284088a8e..f9755d91f7f34 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -7,7 +7,7 @@ import { mark } from 'vs/base/common/performance'; import { domContentLoaded, detectFullscreen, getCookieValue } from 'vs/base/browser/dom'; import { assertIsDefined } from 'vs/base/common/types'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILogService, ConsoleLogger, MultiplexLogService, getLogLevel, ILoggerService } from 'vs/platform/log/common/log'; +import { ILogService, ConsoleLogger, getLogLevel, ILoggerService } from 'vs/platform/log/common/log'; import { ConsoleLogInAutomationLogger } from 'vs/platform/log/browser/log'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { BrowserWorkbenchEnvironmentService, IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; @@ -35,12 +35,11 @@ import { SignService } from 'vs/platform/sign/browser/signService'; import { IWorkbenchConstructionOptions, IWorkbench, ITunnel } from 'vs/workbench/browser/web.api'; import { BrowserStorageService } from 'vs/workbench/services/storage/browser/storageService'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { BufferLogService } from 'vs/platform/log/common/bufferLog'; +import { BufferLogger } from 'vs/platform/log/common/bufferLog'; import { FileLoggerService } from 'vs/platform/log/common/fileLog'; import { toLocalISOString } from 'vs/base/common/date'; import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/window/common/window'; import { getSingleFolderWorkspaceIdentifier, getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; -import { coalesce } from 'vs/base/common/arrays'; import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IndexedDBFileSystemProviderErrorDataClassification, IndexedDBFileSystemProvider, IndexedDBFileSystemProviderErrorData } from 'vs/platform/files/browser/indexedDBFileSystemProvider'; @@ -85,6 +84,7 @@ import { BrowserUserDataProfilesService } from 'vs/platform/userDataProfile/brow import { timeout } from 'vs/base/common/async'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { rendererLogId } from 'vs/workbench/common/logConstants'; +import { LogService } from 'vs/platform/log/common/logService'; export class BrowserMain extends Disposable { @@ -243,7 +243,13 @@ export class BrowserMain extends Disposable { serviceCollection.set(IBrowserWorkbenchEnvironmentService, environmentService); // Log - const logService = new BufferLogService(getLogLevel(environmentService)); + const logLevel = getLogLevel(environmentService); + const bufferLogger = new BufferLogger(logLevel); + const otherLoggers = [new ConsoleLogger(logLevel)]; + if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) { + otherLoggers.push(new ConsoleLogInAutomationLogger(logLevel)); + } + const logService = new LogService(bufferLogger, otherLoggers); serviceCollection.set(ILogService, logService); // Remote @@ -275,10 +281,10 @@ export class BrowserMain extends Disposable { serviceCollection.set(IWorkbenchFileService, fileService); // Logger - const loggerService = new FileLoggerService(logService, fileService); + const loggerService = new FileLoggerService(logLevel, fileService); serviceCollection.set(ILoggerService, loggerService); - await this.registerFileSystemProviders(environmentService, fileService, remoteAgentService, logService, loggerService, logsPath); + await this.registerFileSystemProviders(environmentService, fileService, remoteAgentService, bufferLogger, logService, loggerService, logsPath); // URI Identity const uriIdentityService = new UriIdentityService(fileService); @@ -412,7 +418,7 @@ export class BrowserMain extends Disposable { } } - private async registerFileSystemProviders(environmentService: IWorkbenchEnvironmentService, fileService: IWorkbenchFileService, remoteAgentService: IRemoteAgentService, logService: BufferLogService, loggerService: ILoggerService, logsPath: URI): Promise { + private async registerFileSystemProviders(environmentService: IWorkbenchEnvironmentService, fileService: IWorkbenchFileService, remoteAgentService: IRemoteAgentService, bufferLogger: BufferLogger, logService: ILogService, loggerService: ILoggerService, logsPath: URI): Promise { // IndexedDB is used for logging and user data let indexedDB: IndexedDB | undefined; @@ -437,12 +443,7 @@ export class BrowserMain extends Disposable { fileService.registerProvider(logsPath.scheme, new InMemoryFileSystemProvider()); } - logService.logger = new MultiplexLogService(coalesce([ - new ConsoleLogger(logService.getLevel()), - loggerService.createLogger(environmentService.logFile, { id: rendererLogId, name: localize('rendererLog', "Window") }), - // Extension development test CLI: forward everything to test runner - environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI ? new ConsoleLogInAutomationLogger(logService.getLevel()) : undefined - ])); + bufferLogger.logger = loggerService.createLogger(environmentService.logFile, { id: rendererLogId, name: localize('rendererLog', "Window") }); // User data let userDataProvider; diff --git a/src/vs/workbench/contrib/logs/common/logsActions.ts b/src/vs/workbench/contrib/logs/common/logsActions.ts index 0a083f785eaaf..13e3f66682af6 100644 --- a/src/vs/workbench/contrib/logs/common/logsActions.ts +++ b/src/vs/workbench/contrib/logs/common/logsActions.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { ILogService, ILoggerService, LogLevel, getLogLevel, parseLogLevel } from 'vs/platform/log/common/log'; +import { ILoggerService, LogLevel, getLogLevel, isLogLevel, parseLogLevel } from 'vs/platform/log/common/log'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; @@ -13,7 +13,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { dirname, basename, isEqual } from 'vs/base/common/resources'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IOutputService } from 'vs/workbench/services/output/common/output'; -import { isNumber } from 'vs/base/common/types'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { extensionTelemetryLogChannelId, telemetryLogChannelId } from 'vs/platform/telemetry/common/telemetryUtils'; @@ -21,10 +20,6 @@ import { extensionTelemetryLogChannelId, telemetryLogChannelId } from 'vs/platfo type LogLevelQuickPickItem = IQuickPickItem & { level: LogLevel }; type LogChannelQuickPickItem = IQuickPickItem & { id: string; resource: URI; extensionId?: string }; -function isLogLevel(thing: unknown): thing is LogLevel { - return isNumber(thing); -} - export class SetLogLevelAction extends Action { static readonly ID = 'workbench.action.setLogLevel'; @@ -32,7 +27,6 @@ export class SetLogLevelAction extends Action { constructor(id: string, label: string, @IQuickInputService private readonly quickInputService: IQuickInputService, - @ILogService private readonly logService: ILogService, @ILoggerService private readonly loggerService: ILoggerService, @IOutputService private readonly outputService: IOutputService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @@ -44,7 +38,7 @@ export class SetLogLevelAction extends Action { const logLevelOrChannel = await this.selectLogLevelOrChannel(); if (logLevelOrChannel !== null) { if (isLogLevel(logLevelOrChannel)) { - this.logService.setLevel(logLevelOrChannel); + this.loggerService.setLogLevel(logLevelOrChannel); } else { await this.setLogLevelForChannel(logLevelOrChannel); } @@ -53,7 +47,7 @@ export class SetLogLevelAction extends Action { private async selectLogLevelOrChannel(): Promise { const extensionLogs: LogChannelQuickPickItem[] = [], logs: LogChannelQuickPickItem[] = []; - const logLevel = this.logService.getLevel(); + const logLevel = this.loggerService.getLogLevel(); for (const channel of this.outputService.getChannelDescriptors()) { if (!channel.log || !channel.file || channel.id === telemetryLogChannelId || channel.id === extensionTelemetryLogChannelId) { continue; @@ -68,7 +62,7 @@ export class SetLogLevelAction extends Action { } const entries: (LogLevelQuickPickItem | LogChannelQuickPickItem | IQuickPickSeparator)[] = []; entries.push({ type: 'separator', label: nls.localize('all', "All") }); - entries.push(...this.getLogLevelEntries(this.getDefaultLogLevel(), this.logService.getLevel())); + entries.push(...this.getLogLevelEntries(this.getDefaultLogLevel(), this.loggerService.getLogLevel())); entries.push({ type: 'separator', label: nls.localize('loggers', "Logs") }); entries.push(...logs.sort((a, b) => a.label.localeCompare(b.label))); if (extensionLogs.length && logs.length) { @@ -86,7 +80,7 @@ export class SetLogLevelAction extends Action { const currentLogLevel = this.loggerService.getLogLevel(logChannel.resource) ?? defaultLogLevel; const entries = this.getLogLevelEntries(defaultLogLevel, currentLogLevel); - const entry = await this.quickInputService.pick(entries, { placeHolder: logChannel ? nls.localize('selectLogLevelFor', " {0}: Select log level", logChannel?.label) : nls.localize('selectLogLevel', "Select log level"), activeItem: entries[this.logService.getLevel()] }); + const entry = await this.quickInputService.pick(entries, { placeHolder: logChannel ? nls.localize('selectLogLevelFor', " {0}: Select log level", logChannel?.label) : nls.localize('selectLogLevel', "Select log level"), activeItem: entries[this.loggerService.getLogLevel()] }); if (entry) { this.loggerService.setLogLevel(logChannel.resource, entry.level); } diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index db05bcad30730..06e16322d9481 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -9,11 +9,9 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { ILabelService, ResourceLabelFormatting } from 'vs/platform/label/common/label'; import { OperatingSystem, isWeb, OS } from 'vs/base/common/platform'; import { Schemas } from 'vs/base/common/network'; -import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; -import { LogLevelChannel, LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; import { localize } from 'vs/nls'; -import { joinPath } from 'vs/base/common/resources'; import { Disposable } from 'vs/base/common/lifecycle'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; @@ -31,7 +29,7 @@ import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; import { IDownloadService } from 'vs/platform/download/common/download'; import { DownloadServiceChannel } from 'vs/platform/download/common/downloadIpc'; import { timeout } from 'vs/base/common/async'; -import { TerminalLogConstants } from 'vs/platform/terminal/common/terminal'; +import { RemoteLoggerChannelClient } from 'vs/platform/log/common/logIpc'; export class LabelContribution implements IWorkbenchContribution { constructor( @@ -74,19 +72,9 @@ class RemoteChannelsContribution extends Disposable implements IWorkbenchContrib @ILoggerService loggerService: ILoggerService, ) { super(); - const updateRemoteLogLevel = () => { - const connection = remoteAgentService.getConnection(); - if (!connection) { - return; - } - connection.withChannel('logger', (channel) => LogLevelChannelClient.setLevel(channel, logService.getLevel())); - }; - updateRemoteLogLevel(); - this._register(logService.onDidChangeLogLevel(updateRemoteLogLevel)); const connection = remoteAgentService.getConnection(); if (connection) { connection.registerChannel('download', new DownloadServiceChannel(downloadService)); - connection.registerChannel('logger', new LogLevelChannel(logService, loggerService)); } } } @@ -100,20 +88,7 @@ class RemoteLogOutputChannels extends Disposable implements IWorkbenchContributi super(); const connection = remoteAgentService.getConnection(); if (connection) { - remoteAgentService.getEnvironment().then(remoteEnv => { - if (remoteEnv) { - const remoteServerLog = 'remoteServerLog'; - const remotePtyHostLog = 'remotePtyHostLog'; - loggerService.registerLogger({ id: remoteServerLog, name: localize('remoteExtensionLog', "Remote Server"), resource: joinPath(remoteEnv.logsPath, `${RemoteExtensionLogFileName}.log`) }); - loggerService.registerLogger({ id: remotePtyHostLog, name: localize('remotePtyHostLog', "Remote Pty Host"), resource: joinPath(remoteEnv.logsPath, `${TerminalLogConstants.FileName}.log`) }); - this._register(loggerService.onDidChangeLogLevel(([resource, logLevel]) => { - const logger = loggerService.getRegisteredLogger(resource); - if (logger?.id === remoteServerLog || logger?.id === remotePtyHostLog) { - connection.withChannel('logger', (channel) => LogLevelChannelClient.setLevel(channel, logLevel, resource)); - } - })); - } - }); + connection.withChannel('logger', async channel => this._register(new RemoteLoggerChannelClient(loggerService, channel))); } } } diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index 2615042067364..3701a37421918 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -37,7 +37,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity' import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; import { INativeKeyboardLayoutService, NativeKeyboardLayoutService } from 'vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayoutService'; import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService'; -import { LoggerChannelClient, LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; +import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { NativeLogService } from 'vs/workbench/services/log/electron-sandbox/logService'; import { WorkspaceTrustEnablementService, WorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/common/workspaceTrust'; @@ -170,12 +170,11 @@ export class DesktopMain extends Disposable { serviceCollection.set(INativeWorkbenchEnvironmentService, environmentService); // Logger - const logLevelChannelClient = new LogLevelChannelClient(mainProcessService.getChannel('logLevel')); - const loggerService = new LoggerChannelClient(this.configuration.windowId, this.configuration.logLevel, logLevelChannelClient.onDidChangeLogLevel, this.configuration.loggers, mainProcessService.getChannel('logger')); + const loggerService = new LoggerChannelClient(this.configuration.windowId, this.configuration.logLevel, this.configuration.loggers, mainProcessService.getChannel('logger')); serviceCollection.set(ILoggerService, loggerService); // Log - const logService = this._register(new NativeLogService(`renderer${this.configuration.windowId}`, this.configuration.logLevel, loggerService, logLevelChannelClient, environmentService)); + const logService = this._register(new NativeLogService(this.configuration.logLevel, loggerService, environmentService)); serviceCollection.set(ILogService, logService); if (isCI) { logService.info('workbench#open()'); // marking workbench open helps to diagnose flaky integration/smoke tests diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index 20ece3013e748..c21240deeef13 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -249,9 +249,6 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost throw canceled(); } - // Register logger for web worker exthost log - this._loggerService.registerLogger({ id: 'webWorkerExtHostLog', name: localize('name', "Worker Extension Host"), resource: this._extensionHostLogFile }); - return protocol; } @@ -317,6 +314,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost loggers: [...this._loggerService.getRegisteredLoggers()], logsLocation: this._extensionHostLogsLocation, logFile: this._extensionHostLogFile, + logName: localize('name', "Worker Extension Host"), autoStart: initData.autoStart, remote: { authority: this._environmentService.remoteAuthority, diff --git a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts index cff156573aad6..a78b9e96fc56f 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts @@ -34,6 +34,7 @@ export interface IExtensionHostInitData { loggers: UriDto[]; logsLocation: URI; logFile: URI; + logName: string; autoStart: boolean; remote: { isRemote: boolean; authority: string | undefined; connectionData: IRemoteConnectionData | null }; consoleForward: { includeStack: boolean; logNative: boolean }; diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts index 7e7a50a90a972..d5287bd1d2813 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts @@ -148,14 +148,11 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { reject('The remote extenion host took longer than 60s to send its ready message.'); }, 60 * 1000); - let logFile: URI; - const disposable = protocol.onMessage(msg => { if (isMessageOfType(msg, MessageType.Ready)) { // 1) Extension Host is ready to receive messages, initialize it this._createExtHostInitData(isExtensionDevelopmentDebug).then(data => { - logFile = data.logFile; protocol.send(VSBuffer.fromString(JSON.stringify(data))); }); return; @@ -169,9 +166,6 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { // stop listening for messages here disposable.dispose(); - // Register logger for remote exthost log - this._loggerService.registerLogger({ id: 'remoteExtHostLog', name: localize('remote extension host Log', "Remote Extension Host"), resource: logFile }); - // release this promise this._protocol = protocol; resolve(protocol); @@ -250,6 +244,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { loggers: [...this._loggerService.getRegisteredLoggers()], logsLocation: remoteInitData.extensionHostLogsPath, logFile: joinPath(remoteInitData.extensionHostLogsPath, `${ExtensionHostLogFileName}.log`), + logName: localize('remote extension host Log', "Remote Extension Host"), autoStart: true, uiKind: platform.isWeb ? UIKind.Web : UIKind.Desktop }; diff --git a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts index fa6f3bfb9e9d2..2430ad78dae0e 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts @@ -415,9 +415,6 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost { // stop listening for messages here disposable.dispose(); - // Register logger for exthost log - this._loggerService.registerLogger({ id: 'extHostLog', name: nls.localize('extension host Log', "Extension Host"), resource: this._extensionHostLogFile }); - // release this promise resolve(); return; @@ -474,6 +471,7 @@ export class NativeLocalProcessExtensionHost implements IExtensionHost { loggers: [...this._loggerService.getRegisteredLoggers()], logsLocation: this._environmentService.extHostLogsPath, logFile: this._extensionHostLogFile, + logName: nls.localize('extension host Log', "Extension Host"), autoStart: initData.autoStart, uiKind: UIKind.Desktop }; diff --git a/src/vs/workbench/services/log/electron-sandbox/logService.ts b/src/vs/workbench/services/log/electron-sandbox/logService.ts index a6e33cc60d584..421056d182c0f 100644 --- a/src/vs/workbench/services/log/electron-sandbox/logService.ts +++ b/src/vs/workbench/services/log/electron-sandbox/logService.ts @@ -3,39 +3,32 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { LogService, ConsoleLogger, MultiplexLogService, ILogger, LogLevel } from 'vs/platform/log/common/log'; +import { ConsoleLogger, ILogger, LogLevel } from 'vs/platform/log/common/log'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; -import { LogLevelChannelClient, FollowerLogService, LoggerChannelClient } from 'vs/platform/log/common/logIpc'; +import { LoggerChannelClient } from 'vs/platform/log/common/logIpc'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { localize } from 'vs/nls'; import { rendererLogId } from 'vs/workbench/common/logConstants'; +import { LogService } from 'vs/platform/log/common/logService'; export class NativeLogService extends LogService { - constructor(name: string, logLevel: LogLevel, loggerService: LoggerChannelClient, loggerClient: LogLevelChannelClient, environmentService: INativeWorkbenchEnvironmentService) { + constructor(logLevel: LogLevel, loggerService: LoggerChannelClient, environmentService: INativeWorkbenchEnvironmentService) { const disposables = new DisposableStore(); - const loggers: ILogger[] = []; + const fileLogger = disposables.add(loggerService.createLogger(environmentService.logFile, { id: rendererLogId, name: localize('rendererLog', "Window") })); - // Always log to file - loggers.push(disposables.add(loggerService.createLogger(environmentService.logFile, { id: rendererLogId, name: localize('rendererLog', "Window") }))); - - // Extension development test CLI: forward everything to main side + let consoleLogger: ILogger; if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) { - loggers.push(loggerService.createConsoleMainLogger()); - } - - // Normal mode: Log to console - else { - loggers.push( - disposables.add(new ConsoleLogger(logLevel)), - ); + // Extension development test CLI: forward everything to main side + consoleLogger = loggerService.createConsoleMainLogger(); + } else { + // Normal mode: Log to console + consoleLogger = new ConsoleLogger(logLevel); } - const multiplexLogger = disposables.add(new MultiplexLogService(loggers)); - const followerLogger = disposables.add(new FollowerLogService(loggerClient, multiplexLogger)); - super(followerLogger); + super(fileLogger, [consoleLogger]); this._register(disposables); }