Skip to content

Commit de24732

Browse files
committed
Implement microsoft#39574
1 parent 018cc14 commit de24732

10 files changed

Lines changed: 137 additions & 58 deletions

File tree

src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ import { ipcRenderer } from 'electron';
3838
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
3939
import { createSharedProcessContributions } from 'vs/code/electron-browser/sharedProcess/contrib/contributions';
4040
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
41-
import { ILogService } from 'vs/platform/log/common/log';
41+
import { ILogService, FollowerLogService } from 'vs/platform/log/common/log';
42+
import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc';
4243

4344
export interface ISharedProcessConfiguration {
4445
readonly machineId: string;
@@ -81,7 +82,8 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
8182
const services = new ServiceCollection();
8283

8384
const environmentService = new EnvironmentService(initData.args, process.execPath);
84-
const logService = createSpdLogService('sharedprocess', environmentService);
85+
const logLevelClient = new LogLevelChannelClient(server.getChannel('loglevel', { route: () => 'main' }));
86+
const logService = new FollowerLogService(logLevelClient, createSpdLogService('sharedprocess', environmentService));
8587
process.once('exit', () => logService.dispose());
8688

8789
logService.info('main', JSON.stringify(configuration));

src/vs/code/electron-main/app.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import { DarwinUpdateService } from 'vs/platform/update/electron-main/updateServ
5757
import { IIssueService } from 'vs/platform/issue/common/issue';
5858
import { IssueChannel } from 'vs/platform/issue/common/issueIpc';
5959
import { IssueService } from 'vs/platform/issue/electron-main/issueService';
60+
import { LogLevelChannel } from 'vs/platform/log/common/logIpc';
6061

6162
export class CodeApplication {
6263

@@ -378,6 +379,11 @@ export class CodeApplication {
378379
this.electronIpcServer.registerChannel('windows', windowsChannel);
379380
this.sharedProcessClient.done(client => client.registerChannel('windows', windowsChannel));
380381

382+
// Log level management
383+
const logLevelChannel = new LogLevelChannel(accessor.get(ILogService));
384+
this.electronIpcServer.registerChannel('loglevel', logLevelChannel);
385+
this.sharedProcessClient.done(client => client.registerChannel('loglevel', logLevelChannel));
386+
381387
// Lifecycle
382388
this.lifecycleService.ready();
383389

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

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
'use strict';
77

8-
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
8+
import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log';
99

1010
interface ILog {
1111
level: LogLevel;
@@ -24,17 +24,12 @@ function getLogFunction(logger: ILogService, level: LogLevel): Function {
2424
}
2525
}
2626

27-
export class BufferLogService implements ILogService {
27+
export class BufferLogService extends AbstractLogService implements ILogService {
2828

2929
_serviceBrand: any;
3030
private buffer: ILog[] = [];
3131
private _logger: ILogService | undefined = undefined;
3232

33-
constructor(
34-
private level: LogLevel = LogLevel.Error
35-
) {
36-
}
37-
3833
set logger(logger: ILogService) {
3934
this._logger = logger;
4035

@@ -46,19 +41,11 @@ export class BufferLogService implements ILogService {
4641
this.buffer = [];
4742
}
4843

49-
setLevel(logLevel: LogLevel): void {
50-
this.level = logLevel;
51-
}
52-
53-
getLevel(): LogLevel {
54-
return this.level;
55-
}
56-
5744
private _log(level: LogLevel, args: IArguments): void {
5845
if (this._logger) {
5946
const fn = getLogFunction(this._logger, level);
6047
fn.apply(this._logger, args);
61-
} else if (this.level <= level) {
48+
} else if (this.getLevel() <= level) {
6249
this.buffer.push({ level, args });
6350
}
6451
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc';
7+
import { TPromise } from 'vs/base/common/winjs.base';
8+
import { LogLevel, ILogService } from 'vs/platform/log/common/log';
9+
import Event, { buffer } from 'vs/base/common/event';
10+
11+
export interface ILogLevelManagementChannel extends IChannel {
12+
call(command: 'event:onDidChangeLogLevel'): TPromise<LogLevel>;
13+
call(command: 'setLogLevel', logLevel: LogLevel): TPromise<void>;
14+
}
15+
16+
export class LogLevelChannel implements ILogLevelManagementChannel {
17+
18+
onDidChangeLogLevel: Event<LogLevel>;
19+
20+
constructor(private service: ILogService) {
21+
this.onDidChangeLogLevel = buffer(service.onDidChangeLogLevel, true);
22+
}
23+
24+
call(command: string, arg?: any): TPromise<any> {
25+
switch (command) {
26+
case 'event:onDidChangeLogLevel': return eventToCall(this.onDidChangeLogLevel);
27+
case 'setLogLevel': this.service.setLevel(arg); return TPromise.as(null);
28+
}
29+
return undefined;
30+
}
31+
}
32+
33+
export class LogLevelChannelClient {
34+
35+
constructor(private channel: ILogLevelManagementChannel) { }
36+
37+
private _onDidChangeLogLevel = eventFromCall<LogLevel>(this.channel, 'event:onDidChangeLogLevel');
38+
get onDidChangeLogLevel(): Event<LogLevel> { return this._onDidChangeLogLevel; }
39+
40+
setLogLevel(level: LogLevel): TPromise<void> {
41+
return this.channel.call('setLogLevel', level);
42+
}
43+
}

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

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
'use strict';
77

88
import * as path from 'path';
9-
import { ILogService, LogLevel, NullLogService } from 'vs/platform/log/common/log';
9+
import { ILogService, LogLevel, NullLogService, AbstractLogService } from 'vs/platform/log/common/log';
1010
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
1111
import { RotatingLogger, setAsyncMode } from 'spdlog';
1212

@@ -25,50 +25,44 @@ export function createSpdLogService(processName: string, environmentService: IEn
2525
return new NullLogService();
2626
}
2727

28-
class SpdLogService implements ILogService {
28+
class SpdLogService extends AbstractLogService implements ILogService {
2929

3030
_serviceBrand: any;
3131

3232
constructor(
3333
private readonly logger: RotatingLogger,
34-
private level: LogLevel = LogLevel.Error
34+
level: LogLevel
3535
) {
36-
}
37-
38-
setLevel(logLevel: LogLevel): void {
39-
this.level = logLevel;
40-
}
41-
42-
getLevel(): LogLevel {
43-
return this.level;
36+
super();
37+
this.setLevel(level);
4438
}
4539

4640
trace(): void {
47-
if (this.level <= LogLevel.Trace) {
41+
if (this.getLevel() <= LogLevel.Trace) {
4842
this.logger.trace(this.format(arguments));
4943
}
5044
}
5145

5246
debug(): void {
53-
if (this.level <= LogLevel.Debug) {
47+
if (this.getLevel() <= LogLevel.Debug) {
5448
this.logger.debug(this.format(arguments));
5549
}
5650
}
5751

5852
info(): void {
59-
if (this.level <= LogLevel.Info) {
53+
if (this.getLevel() <= LogLevel.Info) {
6054
this.logger.info(this.format(arguments));
6155
}
6256
}
6357

6458
warn(): void {
65-
if (this.level <= LogLevel.Warning) {
59+
if (this.getLevel() <= LogLevel.Warning) {
6660
this.logger.warn(this.format(arguments));
6761
}
6862
}
6963

7064
error(): void {
71-
if (this.level <= LogLevel.Error) {
65+
if (this.getLevel() <= LogLevel.Error) {
7266
const arg = arguments[0];
7367

7468
if (arg instanceof Error) {
@@ -82,7 +76,7 @@ class SpdLogService implements ILogService {
8276
}
8377

8478
critical(): void {
85-
if (this.level <= LogLevel.Critical) {
79+
if (this.getLevel() <= LogLevel.Critical) {
8680
this.logger.critical(this.format(arguments));
8781
}
8882
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
'use strict';
7+
8+
import { ExtHostContext, IExtHostContext } from '../node/extHost.protocol';
9+
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
10+
import { ILogService } from 'vs/platform/log/common/log';
11+
import { Disposable } from 'vs/base/common/lifecycle';
12+
13+
@extHostCustomer
14+
export class MainThreadLogLevelManagementChannel extends Disposable {
15+
16+
constructor(
17+
extHostContext: IExtHostContext,
18+
@ILogService logService: ILogService,
19+
) {
20+
super();
21+
this._register(logService.onDidChangeLogLevel(level => extHostContext.getProxy(ExtHostContext.ExtHostLogService).$setLogLevel(level)));
22+
}
23+
24+
}

src/vs/workbench/api/node/extHost.protocol.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import { ParsedArgs } from 'vs/platform/environment/common/environment';
5454
import { CommentRule, CharacterPair, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
5555
import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model';
5656
import { ILineMatch, IPatternInfo } from 'vs/platform/search/common/search';
57+
import { LogLevel } from 'vs/platform/log/common/log';
5758

5859
export interface IEnvironment {
5960
isExtensionDevelopmentDebug: boolean;
@@ -744,6 +745,10 @@ export interface ExtHostWindowShape {
744745
$onDidChangeWindowFocus(value: boolean): void;
745746
}
746747

748+
export interface ExtHostLogServiceShape {
749+
$setLogLevel(level: LogLevel);
750+
}
751+
747752
// --- proxy identifiers
748753

749754
export const MainContext = {
@@ -794,7 +799,7 @@ export const ExtHostContext = {
794799
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
795800
ExtHostQuickOpen: createExtId<ExtHostQuickOpenShape>('ExtHostQuickOpen'),
796801
ExtHostExtensionService: createExtId<ExtHostExtensionServiceShape>('ExtHostExtensionService'),
797-
// ExtHostLogService: createExtId<ExtHostLogServiceShape>('ExtHostLogService'),
802+
ExtHostLogService: createExtId<ExtHostLogServiceShape>('ExtHostLogService'),
798803
ExtHostTerminalService: createExtId<ExtHostTerminalServiceShape>('ExtHostTerminalService'),
799804
ExtHostSCM: createExtId<ExtHostSCMShape>('ExtHostSCM'),
800805
ExtHostTask: createExtId<ExtHostTaskShape>('ExtHostTask', ProxyType.CustomMarshaller),

src/vs/workbench/api/node/extHostExtensionService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
150150
this._storagePath = new ExtensionStoragePath(initData.workspace, initData.environment);
151151
this._proxy = extHostContext.getProxy(MainContext.MainThreadExtensionService);
152152
this._activator = null;
153-
this._extHostLogService = new ExtHostLogService(environmentService);
153+
this._extHostLogService = new ExtHostLogService(environmentService, this._logService);
154154

155155
// initialize API first (i.e. do not release barrier until the API is initialized)
156156
const apiFactory = createApiFactory(initData, extHostContext, extHostWorkspace, extHostConfiguration, this, logService);

src/vs/workbench/api/node/extHostLogService.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,47 +8,59 @@ import * as path from 'path';
88
import * as vscode from 'vscode';
99
import { TPromise } from 'vs/base/common/winjs.base';
1010
import { mkdirp, dirExists } from 'vs/base/node/pfs';
11-
import Event, { Emitter } from 'vs/base/common/event';
11+
import Event from 'vs/base/common/event';
1212
import { LogLevel } from 'vs/workbench/api/node/extHostTypes';
1313
import { ILogService } from 'vs/platform/log/common/log';
1414
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
1515
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
1616
import { memoize } from 'vs/base/common/decorators';
17+
import { ExtHostLogServiceShape } from 'vs/workbench/api/node/extHost.protocol';
18+
import { Disposable } from 'vs/base/common/lifecycle';
1719

18-
export class ExtHostLogService {
20+
export class ExtHostLogService extends Disposable implements ExtHostLogServiceShape {
1921
private _loggers: Map<string, ExtHostLogger> = new Map();
2022

21-
constructor(private _environmentService: IEnvironmentService) {
23+
constructor(
24+
private _environmentService: IEnvironmentService,
25+
private _logService: ILogService
26+
) {
27+
super();
28+
}
29+
30+
$setLogLevel(level: LogLevel) {
31+
this._logService.setLevel(level);
2232
}
2333

2434
getExtLogger(extensionID: string): ExtHostLogger {
25-
if (!this._loggers.has(extensionID)) {
26-
const logService = createSpdLogService(extensionID, this._environmentService, extensionID);
27-
const logsDirPath = path.join(this._environmentService.logsPath, extensionID);
28-
this._loggers.set(extensionID, new ExtHostLogger(logService, logsDirPath));
35+
let logger = this._loggers.get(extensionID);
36+
if (!logger) {
37+
logger = this.createLogger(extensionID);
38+
this._loggers.set(extensionID, logger);
2939
}
40+
return logger;
41+
}
3042

31-
return this._loggers.get(extensionID);
43+
private createLogger(extensionID: string): ExtHostLogger {
44+
const logService = createSpdLogService(extensionID, this._environmentService, extensionID);
45+
const logsDirPath = path.join(this._environmentService.logsPath, extensionID);
46+
this._register(this._logService.onDidChangeLogLevel(level => logService.setLevel(level)));
47+
return new ExtHostLogger(logService, logsDirPath);
3248
}
3349
}
3450

3551
export class ExtHostLogger implements vscode.Logger {
36-
private _currentLevel: LogLevel;
37-
private _onDidChangeLogLevel: Emitter<LogLevel>;
3852

3953
constructor(
4054
private readonly _logService: ILogService,
4155
private readonly _logDirectory: string
4256
) {
43-
this._currentLevel = this._logService.getLevel();
44-
this._onDidChangeLogLevel = new Emitter<LogLevel>();
45-
this.onDidChangeLogLevel = this._onDidChangeLogLevel.event;
4657
}
4758

48-
// TODO
49-
readonly onDidChangeLogLevel: Event<LogLevel>;
59+
get onDidChangeLogLevel(): Event<LogLevel> {
60+
return this._logService.onDidChangeLogLevel;
61+
}
5062

51-
get currentLevel(): LogLevel { return this._currentLevel; }
63+
get currentLevel(): LogLevel { return this._logService.getLevel(); }
5264

5365
@memoize
5466
get logDirectory(): TPromise<string> {

src/vs/workbench/electron-browser/main.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
4343
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
4444

4545
import fs = require('fs');
46-
import { ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
46+
import { ConsoleLogService, MultiplexLogService, ILogService, FollowerLogService } from 'vs/platform/log/common/log';
4747
import { IssueChannelClient } from 'vs/platform/issue/common/issueIpc';
4848
import { IIssueService } from 'vs/platform/issue/common/issue';
49+
import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc';
4950
gracefulFs.gracefulify(fs); // enable gracefulFs
5051

5152
export function startup(configuration: IWindowConfiguration): TPromise<void> {
@@ -75,10 +76,7 @@ function openWorkbench(configuration: IWindowConfiguration): TPromise<void> {
7576
const mainServices = createMainProcessServices(mainProcessClient, configuration);
7677

7778
const environmentService = new EnvironmentService(configuration, configuration.execPath);
78-
const spdlogService = createSpdLogService(`renderer${configuration.windowId}`, environmentService);
79-
const consoleLogService = new ConsoleLogService(environmentService);
80-
const logService = new MultiplexLogService([consoleLogService, spdlogService]);
81-
79+
const logService = createLogService(mainProcessClient, configuration, environmentService);
8280
logService.trace('openWorkbench configuration', JSON.stringify(configuration));
8381

8482
// Since the configuration service is one of the core services that is used in so many places, we initialize it
@@ -200,6 +198,14 @@ function createStorageService(workspaceService: IWorkspaceContextService, enviro
200198
return new StorageService(storage, storage, workspaceId, secondaryWorkspaceId);
201199
}
202200

201+
function createLogService(mainProcessClient: ElectronIPCClient, configuration: IWindowConfiguration, environmentService: IEnvironmentService): ILogService {
202+
const spdlogService = createSpdLogService(`renderer${configuration.windowId}`, environmentService);
203+
const consoleLogService = new ConsoleLogService(environmentService);
204+
const logService = new MultiplexLogService([consoleLogService, spdlogService]);
205+
const logLevelClient = new LogLevelChannelClient(mainProcessClient.getChannel('loglevel'));
206+
return new FollowerLogService(logLevelClient, logService);
207+
}
208+
203209
function createMainProcessServices(mainProcessClient: ElectronIPCClient, configuration: IWindowConfiguration): ServiceCollection {
204210
const serviceCollection = new ServiceCollection();
205211

0 commit comments

Comments
 (0)