diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 47f09907617..cc0cb8142e9 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -589,8 +589,7 @@ export abstract class AbstractLoggerService extends Disposable implements ILogge protected abstract doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger; } -export class NullLogService implements ILogService { - declare readonly _serviceBrand: undefined; +export class NullLogger implements ILogger { readonly onDidChangeLogLevel: Event = new Emitter().event; setLevel(level: LogLevel): void { } getLevel(): LogLevel { return LogLevel.Info; } @@ -604,6 +603,19 @@ export class NullLogService implements ILogService { flush(): void { } } +export class NullLogService extends NullLogger implements ILogService { + declare readonly _serviceBrand: undefined; +} + +export class NullLoggerService extends AbstractLoggerService { + + constructor() { super(LogLevel.Info, Event.None); } + + protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions | undefined): ILogger { + return new NullLogger(); + } +} + export function getLogLevel(environmentService: IEnvironmentService): LogLevel { if (environmentService.verbose) { return LogLevel.Trace; diff --git a/src/vs/workbench/contrib/output/common/outputChannelModelService.ts b/src/vs/workbench/contrib/output/common/outputChannelModelService.ts index 3c562328b0c..ec25f0df576 100644 --- a/src/vs/workbench/contrib/output/common/outputChannelModelService.ts +++ b/src/vs/workbench/contrib/output/common/outputChannelModelService.ts @@ -8,7 +8,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IFileService } from 'vs/platform/files/common/files'; import { toLocalISOString } from 'vs/base/common/date'; -import { dirname, joinPath } from 'vs/base/common/resources'; +import { joinPath } from 'vs/base/common/resources'; import { DelegatedOutputChannelModel, FileOutputChannelModel, IOutputChannelModel } from 'vs/workbench/contrib/output/common/outputChannelModel'; import { URI } from 'vs/base/common/uri'; import { ILanguageSelection } from 'vs/editor/common/languages/language'; @@ -22,15 +22,19 @@ export interface IOutputChannelModelService { } -export abstract class AbstractOutputChannelModelService { +export class OutputChannelModelService { declare readonly _serviceBrand: undefined; + private readonly outputLocation: URI; + constructor( - private readonly outputLocation: URI, - @IFileService protected readonly fileService: IFileService, - @IInstantiationService protected readonly instantiationService: IInstantiationService - ) { } + @IFileService private readonly fileService: IFileService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService + ) { + this.outputLocation = joinPath(environmentService.windowLogsPath, `output_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`); + } createOutputChannelModel(id: string, modelUri: URI, language: ILanguageSelection, file?: URI): IOutputChannelModel { return file ? this.instantiationService.createInstance(FileOutputChannelModel, modelUri, language, file) : this.instantiationService.createInstance(DelegatedOutputChannelModel, id, modelUri, language, this.outputDir); @@ -46,15 +50,4 @@ export abstract class AbstractOutputChannelModelService { } -export class OutputChannelModelService extends AbstractOutputChannelModelService implements IOutputChannelModelService { - - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IFileService fileService: IFileService, - ) { - super(joinPath(dirname(environmentService.logFile), toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')), fileService, instantiationService); - } -} - registerSingleton(IOutputChannelModelService, OutputChannelModelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts b/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts deleted file mode 100644 index db0b6be79de..00000000000 --- a/src/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { join } from 'vs/base/common/path'; -import { URI } from 'vs/base/common/uri'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { toLocalISOString } from 'vs/base/common/date'; -import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { AbstractOutputChannelModelService, IOutputChannelModelService } from 'vs/workbench/contrib/output/common/outputChannelModelService'; - -export class OutputChannelModelService extends AbstractOutputChannelModelService implements IOutputChannelModelService { - - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IFileService fileService: IFileService, - @INativeHostService nativeHostService: INativeHostService - ) { - super(URI.file(join(environmentService.logsPath, `output_${nativeHostService.windowId}_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`)), fileService, instantiationService); - } - -} - -registerSingleton(IOutputChannelModelService, OutputChannelModelService, InstantiationType.Delayed); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 2aff66a1e1a..0f3e507ebb0 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -72,7 +72,10 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi } @memoize - get logFile(): URI { return joinPath(this.logsHome, 'window.log'); } + get windowLogsPath(): URI { return this.logsHome; } + + @memoize + get logFile(): URI { return joinPath(this.windowLogsPath, 'window.log'); } @memoize get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.vscodeUserData }); } diff --git a/src/vs/workbench/services/environment/common/environmentService.ts b/src/vs/workbench/services/environment/common/environmentService.ts index c922bb63859..a1b4d8341d1 100644 --- a/src/vs/workbench/services/environment/common/environmentService.ts +++ b/src/vs/workbench/services/environment/common/environmentService.ts @@ -24,6 +24,7 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService { // --- Paths readonly logFile: URI; + readonly windowLogsPath: URI; readonly extHostLogsPath: URI; readonly extHostTelemetryLogFile: URI; diff --git a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts index 1d1498d1c4a..72ee95090af 100644 --- a/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts @@ -86,10 +86,13 @@ export class NativeWorkbenchEnvironmentService extends AbstractNativeEnvironment override get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.vscodeUserData }); } @memoize - get logFile(): URI { return URI.file(join(this.logsPath, `renderer${this.configuration.windowId}.log`)); } + get windowLogsPath(): URI { return URI.file(join(this.logsPath, `window${this.configuration.windowId}`)); } @memoize - get extHostLogsPath(): URI { return URI.file(join(this.logsPath, `exthost${this.configuration.windowId}`)); } + get logFile(): URI { return joinPath(this.windowLogsPath, `renderer.log`); } + + @memoize + get extHostLogsPath(): URI { return joinPath(this.windowLogsPath, 'exthost'); } @memoize get extHostTelemetryLogFile(): URI { diff --git a/src/vs/workbench/services/views/common/viewContainerModel.ts b/src/vs/workbench/services/views/common/viewContainerModel.ts index 4bbed6f5ffd..850c42b99d2 100644 --- a/src/vs/workbench/services/views/common/viewContainerModel.ts +++ b/src/vs/workbench/services/views/common/viewContainerModel.ts @@ -9,16 +9,40 @@ import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget import { Registry } from 'vs/platform/registry/common/platform'; import { Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; import { coalesce, move } from 'vs/base/common/arrays'; import { isUndefined, isUndefinedOrNull } from 'vs/base/common/types'; -import { isEqual } from 'vs/base/common/resources'; +import { isEqual, joinPath } from 'vs/base/common/resources'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { IStringDictionary } from 'vs/base/common/collections'; import { Extensions, IProfileStorageRegistry } from 'vs/workbench/services/userDataProfile/common/userDataProfileStorageRegistry'; import { localize } from 'vs/nls'; -import { ILogService } from 'vs/platform/log/common/log'; +import { ILogger, ILoggerService } from 'vs/platform/log/common/log'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Categories } from 'vs/platform/action/common/actionCommonCategories'; +import { IOutputChannelRegistry, IOutputService, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output'; + +function getViewsLogFile(environmentService: IWorkbenchEnvironmentService): URI { return joinPath(environmentService.windowLogsPath, 'views.log'); } + +registerAction2(class extends Action2 { + constructor() { + super({ + id: '_workbench.output.showViewsLog', + title: { value: 'Show Views Log', original: 'Show Views Log' }, + category: Categories.Developer, + f1: true + }); + } + async run(servicesAccessor: ServicesAccessor): Promise { + const outputService = servicesAccessor.get(IOutputService); + const environmentService = servicesAccessor.get(IWorkbenchEnvironmentService); + Registry.as(OutputExtensions.OutputChannels).registerChannel({ id: 'viewsLog', label: localize('views log', "Views"), file: getViewsLogFile(environmentService), log: true }); + outputService.showChannel('viewsLog'); + + } +}); export function getViewsStateStorageId(viewContainerStorageId: string): string { return `${viewContainerStorageId}.hidden`; } @@ -85,14 +109,19 @@ class ViewDescriptorsState extends Disposable { private _onDidChangeStoredState = this._register(new Emitter<{ id: string; visible: boolean }[]>()); readonly onDidChangeStoredState = this._onDidChangeStoredState.event; + private readonly logger: ILogger; + constructor( viewContainerStorageId: string, viewContainerName: string, @IStorageService private readonly storageService: IStorageService, - @ILogService private readonly logService: ILogService, + @ILoggerService loggerService: ILoggerService, + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { super(); + this.logger = loggerService.createLogger(getViewsLogFile(workbenchEnvironmentService)); + this.globalViewsStateStorageId = getViewsStateStorageId(viewContainerStorageId); this.workspaceViewsStateStorageId = viewContainerStorageId; this._register(this.storageService.onDidChangeValue(e => this.onDidStorageChange(e))); @@ -165,7 +194,7 @@ class ViewDescriptorsState extends Disposable { if (state) { if (state.visibleGlobal !== !storedState.isHidden) { if (!storedState.isHidden) { - this.logService.info(`View visibility state changed: ${id} is now visible`); + this.logger.info(`View visibility state changed: ${id} is now visible`); } changedStates.push({ id, visible: !storedState.isHidden }); } @@ -349,14 +378,19 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode private _onDidMoveVisibleViewDescriptors = this._register(new Emitter<{ from: IViewDescriptorRef; to: IViewDescriptorRef }>()); readonly onDidMoveVisibleViewDescriptors: Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef }> = this._onDidMoveVisibleViewDescriptors.event; + private readonly logger: ILogger; + constructor( readonly viewContainer: ViewContainer, @IInstantiationService instantiationService: IInstantiationService, @IContextKeyService private readonly contextKeyService: IContextKeyService, - @ILogService private readonly logService: ILogService, + @ILoggerService loggerService: ILoggerService, + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { super(); + this.logger = loggerService.createLogger(getViewsLogFile(workbenchEnvironmentService)); + this._register(Event.filter(contextKeyService.onDidChangeContext, e => e.affectsSome(this.contextKeys))(() => this.onDidChangeContext())); this.viewDescriptorsState = this._register(instantiationService.createInstance(ViewDescriptorsState, viewContainer.storageId || `${viewContainer.id}.state`, typeof viewContainer.title === 'string' ? viewContainer.title : viewContainer.title.original)); this._register(this.viewDescriptorsState.onDidChangeStoredState(items => this.updateVisibility(items))); @@ -366,7 +400,7 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode Event.map(this.onDidRemoveVisibleViewDescriptors, removed => `Removed views:${removed.map(v => v.viewDescriptor.id).join(',')}`), Event.map(this.onDidMoveVisibleViewDescriptors, ({ from, to }) => `Moved view ${from.viewDescriptor.id} to ${to.viewDescriptor.id}`)) (message => { - this.logService.info(message); + this.logger.info(message); this.viewDescriptorsState.updateState(this.allViewDescriptors); this.updateContainerInfo(); })); @@ -472,7 +506,7 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode } else { viewDescriptorItem.state.visibleGlobal = visible; if (visible) { - this.logService.info(`Showing view ${viewDescriptorItem.viewDescriptor.id} in the container ${this.viewContainer.id}`); + this.logger.info(`Showing view ${viewDescriptorItem.viewDescriptor.id} in the container ${this.viewContainer.id}`); } } @@ -545,7 +579,7 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode const isVisible = state.visibleGlobal; state.visibleGlobal = isUndefinedOrNull(addedViewDescriptorState.visible) ? (isUndefinedOrNull(state.visibleGlobal) ? !viewDescriptor.hideByDefault : state.visibleGlobal) : addedViewDescriptorState.visible; if (state.visibleGlobal && !isVisible) { - this.logService.info(`Added view ${viewDescriptor.id} in the container ${this.viewContainer.id} and showing it`); + this.logger.info(`Added view ${viewDescriptor.id} in the container ${this.viewContainer.id} and showing it`); } } state.collapsed = isUndefinedOrNull(addedViewDescriptorState.collapsed) ? (isUndefinedOrNull(state.collapsed) ? !!viewDescriptor.collapsed : state.collapsed) : addedViewDescriptorState.collapsed; diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index c41b5c65a67..796e5fc4fe3 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -56,7 +56,7 @@ import { IEditorService, ISaveEditorsOptions, IRevertAllEditorsOptions, Preferre import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; import { Dimension, IDimension } from 'vs/base/browser/dom'; -import { ILogService, NullLogService } from 'vs/platform/log/common/log'; +import { ILoggerService, ILogService, NullLoggerService, NullLogService } from 'vs/platform/log/common/log'; import { ILabelService } from 'vs/platform/label/common/label'; import { timeout } from 'vs/base/common/async'; import { PaneComposite, PaneCompositeDescriptor } from 'vs/workbench/browser/panecomposite'; @@ -302,6 +302,7 @@ export function workbenchInstantiationService( instantiationService.stub(ITextFileService, overrides?.textFileService ? overrides.textFileService(instantiationService) : disposables.add(instantiationService.createInstance(TestTextFileService))); instantiationService.stub(IHostService, instantiationService.createInstance(TestHostService)); instantiationService.stub(ITextModelService, disposables.add(instantiationService.createInstance(TextModelResolverService))); + instantiationService.stub(ILoggerService, new NullLoggerService()); instantiationService.stub(ILogService, new NullLogService()); const editorGroupService = new TestEditorGroupsService([new TestEditorGroupView(0)]); instantiationService.stub(IEditorGroupsService, editorGroupService); @@ -479,7 +480,7 @@ class TestEnvironmentServiceWithArgs extends BrowserWorkbenchEnvironmentService args = []; } -export const TestEnvironmentService = new TestEnvironmentServiceWithArgs('', undefined!, Object.create(null), TestProductService); +export const TestEnvironmentService = new TestEnvironmentServiceWithArgs('', URI.file('tests').with({ scheme: 'vscode-tests' }), Object.create(null), TestProductService); export class TestProgressService implements IProgressService { diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index bf9f350efe9..01588f36305 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -234,6 +234,7 @@ import 'vs/workbench/contrib/extensions/browser/extensions.contribution'; import 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; // Output View +import 'vs/workbench/contrib/output/common/outputChannelModelService'; import 'vs/workbench/contrib/output/browser/output.contribution'; import 'vs/workbench/contrib/output/browser/outputView'; diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index ca74c51637b..aa0846dcb24 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -133,9 +133,6 @@ import 'vs/workbench/contrib/themes/browser/themes.test.contribution'; // User Data Sync import 'vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution'; -// Output -import 'vs/workbench/contrib/output/electron-sandbox/outputChannelModelService'; - // Tags import 'vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService'; import 'vs/workbench/contrib/tags/electron-sandbox/tags.contribution'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 1462d032fe5..286ab2b2f22 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -112,9 +112,6 @@ registerSingleton(ILanguagePackService, WebLanguagePacksService, InstantiationTy //#region --- workbench contributions -// Output -import 'vs/workbench/contrib/output/common/outputChannelModelService'; - // Logs import 'vs/workbench/contrib/logs/browser/logs.contribution';