Skip to content

Commit 9914a95

Browse files
committed
buffer spdlog calls in main until singleton
fixes microsoft#41218
1 parent e5cbf75 commit 9914a95

8 files changed

Lines changed: 120 additions & 17 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
3737
import { ipcRenderer } from 'electron';
3838
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
3939
import { createSharedProcessContributions } from 'vs/code/electron-browser/sharedProcess/contrib/contributions';
40-
import { createLogService } from 'vs/platform/log/node/spdlogService';
40+
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
4141
import { ILogService } from 'vs/platform/log/common/log';
4242

4343
export interface ISharedProcessConfiguration {
@@ -81,7 +81,7 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
8181
const services = new ServiceCollection();
8282

8383
const environmentService = new EnvironmentService(initData.args, process.execPath);
84-
const logService = createLogService('sharedprocess', environmentService);
84+
const logService = createSpdLogService('sharedprocess', environmentService);
8585
process.once('exit', () => logService.dispose());
8686

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

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@ import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/work
4242
import { IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces';
4343
import { localize } from 'vs/nls';
4444
import { mnemonicButtonLabel } from 'vs/base/common/labels';
45-
import { createLogService } from 'vs/platform/log/node/spdlogService';
45+
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
4646
import { printDiagnostics } from 'vs/code/electron-main/diagnostics';
47+
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
4748

48-
function createServices(args: ParsedArgs): IInstantiationService {
49+
function createServices(args: ParsedArgs, bufferLogService: BufferLogService): IInstantiationService {
4950
const services = new ServiceCollection();
5051

5152
const environmentService = new EnvironmentService(args, process.execPath);
52-
const spdlogService = createLogService('main', environmentService);
5353
const consoleLogService = new ConsoleLogMainService(environmentService);
54-
const logService = new MultiplexLogService([consoleLogService, spdlogService]);
54+
const logService = new MultiplexLogService([consoleLogService, bufferLogService]);
5555

5656
process.once('exit', () => logService.dispose());
5757

@@ -284,7 +284,12 @@ function main() {
284284
return;
285285
}
286286

287-
const instantiationService = createServices(args);
287+
// We need to buffer the spdlog logs until we are sure
288+
// we are the only instance running, otherwise we'll have concurrent
289+
// log file access on Windows
290+
// https://github.com/Microsoft/vscode/issues/41218
291+
const bufferLogService = new BufferLogService();
292+
const instantiationService = createServices(args, bufferLogService);
288293

289294
return instantiationService.invokeFunction(accessor => {
290295

@@ -300,7 +305,10 @@ function main() {
300305
// Startup
301306
return instantiationService.invokeFunction(a => createPaths(a.get(IEnvironmentService)))
302307
.then(() => instantiationService.invokeFunction(setupIPC))
303-
.then(mainIpcServer => instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnv).startup());
308+
.then(mainIpcServer => {
309+
bufferLogService.logger = createSpdLogService('main', environmentService);
310+
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnv).startup();
311+
});
304312
}).done(null, err => instantiationService.invokeFunction(quit, err));
305313
}
306314

src/vs/code/node/cliProcessMain.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { ChoiceCliService } from 'vs/platform/message/node/messageCli';
3535
import { getBaseLabel } from 'vs/base/common/labels';
3636
import { IStateService } from 'vs/platform/state/common/state';
3737
import { StateService } from 'vs/platform/state/node/stateService';
38-
import { createLogService } from 'vs/platform/log/node/spdlogService';
38+
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
3939
import { ILogService } from 'vs/platform/log/common/log';
4040
import { isPromiseCanceledError } from 'vs/base/common/errors';
4141

@@ -196,7 +196,7 @@ export function main(argv: ParsedArgs): TPromise<void> {
196196
const services = new ServiceCollection();
197197

198198
const environmentService = new EnvironmentService(argv, process.execPath);
199-
const logService = createLogService('cli', environmentService);
199+
const logService = createSpdLogService('cli', environmentService);
200200
process.once('exit', () => logService.dispose());
201201

202202
logService.info('main', argv);
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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 { ILogService, LogLevel } from 'vs/platform/log/common/log';
9+
10+
interface ILog {
11+
level: LogLevel;
12+
args: IArguments;
13+
}
14+
15+
function getLogFunction(logger: ILogService, level: LogLevel): Function {
16+
switch (level) {
17+
case LogLevel.Trace: return logger.trace;
18+
case LogLevel.Debug: return logger.debug;
19+
case LogLevel.Info: return logger.info;
20+
case LogLevel.Warning: return logger.warn;
21+
case LogLevel.Error: return logger.error;
22+
case LogLevel.Critical: return logger.critical;
23+
default: throw new Error('Invalid log level');
24+
}
25+
}
26+
27+
export class BufferLogService implements ILogService {
28+
29+
_serviceBrand: any;
30+
private buffer: ILog[] = [];
31+
private _logger: ILogService | undefined = undefined;
32+
33+
constructor(
34+
private level: LogLevel = LogLevel.Error
35+
) {
36+
}
37+
38+
set logger(logger: ILogService) {
39+
this._logger = logger;
40+
41+
for (const { level, args } of this.buffer) {
42+
const fn = getLogFunction(logger, level);
43+
fn.apply(logger, args);
44+
}
45+
46+
this.buffer = [];
47+
}
48+
49+
setLevel(logLevel: LogLevel): void {
50+
this.level = logLevel;
51+
}
52+
53+
getLevel(): LogLevel {
54+
return this.level;
55+
}
56+
57+
private _log(level: LogLevel, args: IArguments): void {
58+
if (this._logger) {
59+
const fn = getLogFunction(this._logger, level);
60+
fn.apply(this._logger, args);
61+
} else if (this.level < level) {
62+
this.buffer.push({ level, args });
63+
}
64+
}
65+
66+
trace(): void {
67+
this._log(LogLevel.Trace, arguments);
68+
}
69+
70+
debug(): void {
71+
this._log(LogLevel.Debug, arguments);
72+
}
73+
74+
info(): void {
75+
this._log(LogLevel.Info, arguments);
76+
}
77+
78+
warn(): void {
79+
this._log(LogLevel.Warning, arguments);
80+
}
81+
82+
error(): void {
83+
this._log(LogLevel.Error, arguments);
84+
}
85+
86+
critical(): void {
87+
this._log(LogLevel.Critical, arguments);
88+
}
89+
90+
dispose(): void {
91+
if (this._logger) {
92+
this._logger.dispose();
93+
}
94+
}
95+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { ILogService, LogLevel, NullLogService } from 'vs/platform/log/common/lo
1010
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
1111
import { RotatingLogger, setAsyncMode } from 'spdlog';
1212

13-
export function createLogService(processName: string, environmentService: IEnvironmentService, logsSubfolder?: string): ILogService {
13+
export function createSpdLogService(processName: string, environmentService: IEnvironmentService, logsSubfolder?: string): ILogService {
1414
try {
1515
setAsyncMode(8192, 2000);
1616
const logsDirPath = logsSubfolder ? path.join(environmentService.logsPath, logsSubfolder) : environmentService.logsPath;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { mkdirp, dirExists } from 'vs/base/node/pfs';
1111
import Event, { Emitter } from 'vs/base/common/event';
1212
import { LogLevel } from 'vs/workbench/api/node/extHostTypes';
1313
import { ILogService } from 'vs/platform/log/common/log';
14-
import { createLogService } from 'vs/platform/log/node/spdlogService';
14+
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';
1717

@@ -23,7 +23,7 @@ export class ExtHostLogService {
2323

2424
getExtLogger(extensionID: string): ExtHostLogger {
2525
if (!this._loggers.has(extensionID)) {
26-
const logService = createLogService(extensionID, this._environmentService, extensionID);
26+
const logService = createSpdLogService(extensionID, this._environmentService, extensionID);
2727
const logsDirPath = path.join(this._environmentService.logsPath, extensionID);
2828
this._loggers.set(extensionID, new ExtHostLogger(logService, logsDirPath));
2929
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import { URLChannelClient } from 'vs/platform/url/common/urlIpc';
4040
import { IURLService } from 'vs/platform/url/common/url';
4141
import { WorkspacesChannelClient } from 'vs/platform/workspaces/common/workspacesIpc';
4242
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
43-
import { createLogService } from 'vs/platform/log/node/spdlogService';
43+
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
4444

4545
import fs = require('fs');
4646
import { ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
@@ -73,7 +73,7 @@ function openWorkbench(configuration: IWindowConfiguration): TPromise<void> {
7373
const mainServices = createMainProcessServices(mainProcessClient, configuration);
7474

7575
const environmentService = new EnvironmentService(configuration, configuration.execPath);
76-
const spdlogService = createLogService(`renderer${configuration.windowId}`, environmentService);
76+
const spdlogService = createSpdLogService(`renderer${configuration.windowId}`, environmentService);
7777
const consoleLogService = new ConsoleLogService(environmentService);
7878
const logService = new MultiplexLogService([consoleLogService, spdlogService]);
7979

src/vs/workbench/node/extensionHostMain.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import * as watchdog from 'native-watchdog';
2121
import * as glob from 'vs/base/common/glob';
2222
import { ExtensionActivatedByEvent } from 'vs/workbench/api/node/extHostExtensionActivator';
2323
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
24-
import { createLogService } from 'vs/platform/log/node/spdlogService';
24+
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
2525
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
2626
import { ILogService } from 'vs/platform/log/common/log';
2727
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
@@ -92,7 +92,7 @@ export class ExtensionHostMain {
9292
const rpcProtocol = new RPCProtocol(protocol);
9393
const extHostWorkspace = new ExtHostWorkspace(rpcProtocol, initData.workspace);
9494
const environmentService = new EnvironmentService(initData.args, initData.execPath);
95-
this._logService = createLogService(`exthost${initData.windowId}`, environmentService);
95+
this._logService = createSpdLogService(`exthost${initData.windowId}`, environmentService);
9696
this.disposables.push(this._logService);
9797

9898
this._logService.info('extension host started');

0 commit comments

Comments
 (0)