Merge pull request #39365 from Microsoft/joao/spdlog

Introduce a log service across all processes
This commit is contained in:
João Moreno 2017-12-04 13:19:17 +01:00 committed by GitHub
commit 4b91235ba2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 495 additions and 155 deletions

View file

@ -297,6 +297,7 @@ function packageTask(platform, arch, opts) {
.pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('native-watchdog', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('spdlog', ['binding.gyp', 'build/**', 'deps/**', 'src/**', 'test/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('jschardet', ['dist/**']))
.pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))
.pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node']))

View file

@ -37,6 +37,7 @@
"node-pty": "0.7.3",
"nsfw": "1.0.16",
"semver": "4.3.6",
"spdlog": "0.2.1",
"v8-inspect-profiler": "^0.0.6",
"vscode-chokidar": "1.6.2",
"vscode-debugprotocol": "1.25.0-pre.0",
@ -126,4 +127,4 @@
"windows-mutex": "^0.2.0",
"windows-process-tree": "0.1.6"
}
}
}

33
src/typings/spdlog.d.ts vendored Normal file
View file

@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'spdlog' {
export const version: string;
export function setAsyncMode(bufferSize: number, flushInterval: number);
export enum LogLevel {
CRITICAL,
ERROR,
WARN,
INFO,
DEBUG,
TRACE,
OFF
}
export class RotatingLogger {
constructor(name: string, filename: string, filesize: number, filecount: number);
trace(message: string);
debug(message: string);
info(message: string);
warn(message: string);
error(message: string);
critical(message: string);
setLevel(level: number);
flush(): void;
}
}

View file

@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
function pad(number: number): string {
if (number < 10) {
return '0' + number;
}
return String(number);
}
export function toLocalISOString(date: Date): string {
return date.getFullYear() +
'-' + pad(date.getMonth() + 1) +
'-' + pad(date.getDate()) +
'T' + pad(date.getHours()) +
':' + pad(date.getMinutes()) +
':' + pad(date.getSeconds()) +
'.' + (date.getMilliseconds() / 1000).toFixed(3).slice(2, 5) +
'Z';
}

View file

@ -35,6 +35,8 @@ import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
import { ipcRenderer } from 'electron';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { createSharedProcessContributions } from 'vs/code/electron-browser/contrib/contributions';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { ILogService, registerGlobalLogService } from 'vs/platform/log/common/log';
export interface ISharedProcessConfiguration {
readonly machineId: string;
@ -76,7 +78,14 @@ const eventPrefix = 'monacoworkbench';
function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): void {
const services = new ServiceCollection();
services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService, initData.args, process.execPath));
const environmentService = new EnvironmentService(initData.args, process.execPath);
const logService = new SpdLogService('sharedprocess', environmentService);
registerGlobalLogService(logService);
logService.info('main', JSON.stringify(configuration));
services.set(IEnvironmentService, environmentService);
services.set(ILogService, logService);
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
services.set(IRequestService, new SyncDescriptor(RequestService));

View file

@ -109,7 +109,7 @@ export class CodeApplication {
});
app.on('will-quit', () => {
this.logService.info('App#will-quit: disposing resources');
this.logService.trace('App#will-quit: disposing resources');
this.dispose();
});
@ -121,7 +121,7 @@ export class CodeApplication {
});
app.on('activate', (event: Event, hasVisibleWindows: boolean) => {
this.logService.info('App#activate');
this.logService.trace('App#activate');
// Mac only event: open new window when we get activated
if (!hasVisibleWindows && this.windowsMainService) {
@ -156,7 +156,7 @@ export class CodeApplication {
let macOpenFiles: string[] = [];
let runningTimeout: number = null;
app.on('open-file', (event: Event, path: string) => {
this.logService.info('App#open-file: ', path);
this.logService.trace('App#open-file: ', path);
event.preventDefault();
// Keep in array because more might come!
@ -188,7 +188,7 @@ export class CodeApplication {
});
ipc.on('vscode:exit', (_event: any, code: number) => {
this.logService.info('IPC#vscode:exit', code);
this.logService.trace('IPC#vscode:exit', code);
this.dispose();
this.lifecycleService.kill(code);
@ -211,7 +211,7 @@ export class CodeApplication {
ipc.on('vscode:broadcast', (_event: any, windowId: number, broadcast: { channel: string; payload: any; }) => {
if (this.windowsMainService && broadcast.channel && !isUndefinedOrNull(broadcast.payload)) {
this.logService.info('IPC#vscode:broadcast', broadcast.channel, broadcast.payload);
this.logService.trace('IPC#vscode:broadcast', broadcast.channel, broadcast.payload);
// Handle specific events on main side
this.onBroadcast(broadcast.channel, broadcast.payload);
@ -241,9 +241,9 @@ export class CodeApplication {
}
public startup(): TPromise<void> {
this.logService.info('Starting VS Code in verbose mode');
this.logService.info(`from: ${this.environmentService.appRoot}`);
this.logService.info('args:', this.environmentService.args);
this.logService.debug('Starting VS Code');
this.logService.debug(`from: ${this.environmentService.appRoot}`);
this.logService.debug('args:', this.environmentService.args);
// Make sure we associate the program with the app user model id
// This will help Windows to associate the running program with
@ -257,9 +257,9 @@ export class CodeApplication {
this.electronIpcServer = new ElectronIPCServer();
// Resolve unique machine ID
this.logService.info('Resolving machine identifier...');
this.logService.trace('Resolving machine identifier...');
return this.resolveMachineId().then(machineId => {
this.logService.info(`Resolved machine identifier: ${machineId}`);
this.logService.trace(`Resolved machine identifier: ${machineId}`);
// Spawn shared process
this.sharedProcess = new SharedProcess(this.environmentService, machineId, this.userEnv);

View file

@ -102,7 +102,7 @@ export class LaunchService implements ILaunchService {
) { }
public start(args: ParsedArgs, userEnv: IProcessEnvironment): TPromise<void> {
this.logService.info('Received data from other instance: ', args, userEnv);
this.logService.trace('Received data from other instance: ', args, userEnv);
// Check early for open-url which is handled in URL service
const openUrlArg = args['open-url'] || [];
@ -149,13 +149,13 @@ export class LaunchService implements ILaunchService {
}
public getMainProcessId(): TPromise<number> {
this.logService.info('Received request for process ID from other instance.');
this.logService.trace('Received request for process ID from other instance.');
return TPromise.as(process.pid);
}
public getMainProcessInfo(): TPromise<IMainProcessInfo> {
this.logService.info('Received request for main process info from other instance.');
this.logService.trace('Received request for main process info from other instance.');
return TPromise.wrap({
mainPID: process.pid,

View file

@ -20,7 +20,7 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ILogService, LegacyLogMainService } from 'vs/platform/log/common/log';
import { ILogService, LegacyLogMainService, MultiplexLogService, registerGlobalLogService } from 'vs/platform/log/common/log';
import { StateService } from 'vs/platform/state/node/stateService';
import { IStateService } from 'vs/platform/state/common/state';
import { IBackupMainService } from 'vs/platform/backup/common/backup';
@ -41,13 +41,23 @@ import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/work
import { IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces';
import { localize } from 'vs/nls';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { printDiagnostics } from 'vs/code/electron-main/diagnostics';
function createServices(args: ParsedArgs): IInstantiationService {
const services = new ServiceCollection();
services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService, args, process.execPath));
services.set(ILogService, new SyncDescriptor(LegacyLogMainService, 'main'));
const environmentService = new EnvironmentService(args, process.execPath);
const spdlogService = new SpdLogService('main', environmentService);
const legacyLogService = new LegacyLogMainService(environmentService);
const logService = new MultiplexLogService([legacyLogService, spdlogService]);
registerGlobalLogService(logService);
// Eventually cleanup
setTimeout(() => spdlogService.cleanup().then(null, err => console.error(err)), 10000);
services.set(IEnvironmentService, environmentService);
services.set(ILogService, logService);
services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService));
services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService));
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
@ -64,7 +74,8 @@ function createPaths(environmentService: IEnvironmentService): TPromise<any> {
const paths = [
environmentService.appSettingsHome,
environmentService.extensionsPath,
environmentService.nodeCachedDataDir
environmentService.nodeCachedDataDir,
environmentService.logsPath
];
return TPromise.join(paths.map(p => p && mkdirp(p))) as TPromise<any>;
}
@ -82,7 +93,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
if (platform.isWindows) {
promise = service.getMainProcessId()
.then(processId => {
logService.info('Sending some foreground love to the running instance:', processId);
logService.trace('Sending some foreground love to the running instance:', processId);
try {
const { allowSetForegroundWindow } = <any>require.__$__nodeRequire('windows-foreground-love');
@ -157,7 +168,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
});
}
logService.info('Sending env to running instance...');
logService.trace('Sending env to running instance...');
return allowSetForegroundWindow(service)
.then(() => service.start(environmentService.args, process.env))
@ -190,7 +201,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
try {
fs.unlinkSync(environmentService.mainIPCHandle);
} catch (e) {
logService.info('Fatal error deleting obsolete instance handle', e);
logService.warn('Could not delete obsolete instance handle', e);
return TPromise.wrapError<Server>(e);
}
@ -258,7 +269,8 @@ function main() {
const environmentService = accessor.get(IEnvironmentService);
const instanceEnv: typeof process.env = {
VSCODE_IPC_HOOK: environmentService.mainIPCHandle,
VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG']
VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'],
VSCODE_LOGS: process.env['VSCODE_LOGS']
};
assign(process.env, instanceEnv);

View file

@ -207,7 +207,7 @@ export class CodeWindow implements ICodeWindow {
}
}
} catch (err) {
this.logService.info(`Unexpected error fixing window position on windows with multiple windows: ${err}\n${err.stack}`);
this.logService.warn(`Unexpected error fixing window position on windows with multiple windows: ${err}\n${err.stack}`);
}
}
@ -680,7 +680,7 @@ export class CodeWindow implements ICodeWindow {
try {
state = this.validateWindowState(state);
} catch (err) {
this.logService.info(`Unexpected error validating window state: ${err}\n${err.stack}`); // somehow display API can be picky about the state to validate
this.logService.warn(`Unexpected error validating window state: ${err}\n${err.stack}`); // somehow display API can be picky about the state to validate
}
}

View file

@ -203,7 +203,7 @@ export class WindowsManager implements IWindowsMainService {
// React to workbench loaded events from windows
ipc.on('vscode:workbenchLoaded', (_event: any, windowId: number) => {
this.logService.info('IPC#vscode-workbenchLoaded');
this.logService.trace('IPC#vscode-workbenchLoaded');
const win = this.getWindowById(windowId);
if (win) {

View file

@ -34,7 +34,7 @@ suite('BackupMainService', () => {
class TestBackupMainService extends BackupMainService {
constructor(backupHome: string, backupWorkspacesPath: string, configService: TestConfigurationService) {
super(environmentService, configService, new LegacyLogMainService('test', environmentService));
super(environmentService, configService, new LegacyLogMainService(environmentService));
this.backupHome = backupHome;
this.workspacesJsonPath = backupWorkspacesPath;

View file

@ -11,7 +11,7 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import Event, { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { log, LogLevel, ILogService } from 'vs/platform/log/common/log';
import { log, LogLevel } from 'vs/platform/log/common/log';
export class CommandService extends Disposable implements ICommandService {
@ -25,15 +25,13 @@ export class CommandService extends Disposable implements ICommandService {
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IExtensionService private _extensionService: IExtensionService,
@IContextKeyService private _contextKeyService: IContextKeyService,
// @ts-ignore
@ILogService private logService: ILogService
@IContextKeyService private _contextKeyService: IContextKeyService
) {
super();
this._extensionService.whenInstalledExtensionsRegistered().then(value => this._extensionHostIsReady = value);
}
@log(LogLevel.INFO, 'CommandService', (msg, id) => `${msg}(${id})`)
@log(LogLevel.Info, 'CommandService', (msg, id) => `${msg}(${id})`)
executeCommand<T>(id: string, ...args: any[]): TPromise<T> {
// we always send an activation event, but
// we don't wait for it when the extension

View file

@ -16,7 +16,6 @@ import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyServ
import { SimpleConfigurationService } from 'vs/editor/standalone/browser/simpleServices';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import Event, { Emitter } from 'vs/base/common/event';
import { NoopLogService } from 'vs/platform/log/common/log';
class SimpleExtensionService implements IExtensionService {
_serviceBrand: any;
@ -75,7 +74,7 @@ suite('CommandService', function () {
lastEvent = activationEvent;
return super.activateByEvent(activationEvent);
}
}, new ContextKeyService(new SimpleConfigurationService()), new NoopLogService());
}, new ContextKeyService(new SimpleConfigurationService()));
return service.executeCommand('foo').then(() => {
assert.ok(lastEvent, 'onCommand:foo');
@ -93,7 +92,7 @@ suite('CommandService', function () {
activateByEvent(activationEvent: string): TPromise<void> {
return TPromise.wrapError<void>(new Error('bad_activate'));
}
}, new ContextKeyService(new SimpleConfigurationService()), new NoopLogService());
}, new ContextKeyService(new SimpleConfigurationService()));
return service.executeCommand('foo').then(() => assert.ok(false), err => {
assert.equal(err.message, 'bad_activate');
@ -109,7 +108,7 @@ suite('CommandService', function () {
whenInstalledExtensionsRegistered() {
return new TPromise<boolean>(_resolve => { /*ignore*/ });
}
}, new ContextKeyService(new SimpleConfigurationService()), new NoopLogService());
}, new ContextKeyService(new SimpleConfigurationService()));
service.executeCommand('bar');
assert.equal(callCounter, 1);
@ -126,7 +125,7 @@ suite('CommandService', function () {
whenInstalledExtensionsRegistered() {
return new TPromise<boolean>(_resolve => { resolveFunc = _resolve; });
}
}, new ContextKeyService(new SimpleConfigurationService()), new NoopLogService());
}, new ContextKeyService(new SimpleConfigurationService()));
let r = service.executeCommand('bar');
assert.equal(callCounter, 0);
@ -145,8 +144,7 @@ suite('CommandService', function () {
let commandService = new CommandService(
new InstantiationService(),
new SimpleExtensionService(),
contextKeyService,
new NoopLogService()
contextKeyService
);
let counter = 0;

View file

@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { LogLevel } from 'vs/platform/log/common/log';
export interface ParsedArgs {
[arg: string]: any;
@ -25,6 +26,7 @@ export interface ParsedArgs {
'prof-startup'?: string;
'prof-startup-prefix'?: string;
verbose?: boolean;
log?: string;
logExtensionHostCommunication?: boolean;
'disable-extensions'?: boolean;
'extensions-dir'?: string;
@ -100,10 +102,14 @@ export interface IEnvironmentService {
logExtensionHostCommunication: boolean;
isBuilt: boolean;
verbose: boolean;
wait: boolean;
performance: boolean;
// logging
logsPath: string;
verbose: boolean;
logLevel: LogLevel;
skipGettingStarted: boolean | undefined;
skipAddToRecentlyOpened: boolean;

View file

@ -12,6 +12,8 @@ import URI from 'vs/base/common/uri';
import { memoize } from 'vs/base/common/decorators';
import pkg from 'vs/platform/node/package';
import product from 'vs/platform/node/product';
import { LogLevel } from 'vs/platform/log/common/log';
import { toLocalISOString } from 'vs/base/common/date';
// Read this before there's any chance it is overwritten
// Related to https://github.com/Microsoft/vscode/issues/30624
@ -49,6 +51,8 @@ export class EnvironmentService implements IEnvironmentService {
get execPath(): string { return this._execPath; }
readonly logsPath: string;
@memoize
get userHome(): string { return os.homedir(); }
@ -112,6 +116,34 @@ export class EnvironmentService implements IEnvironmentService {
get isBuilt(): boolean { return !process.env['VSCODE_DEV']; }
get verbose(): boolean { return this._args.verbose; }
@memoize
get logLevel(): LogLevel {
if (this.verbose) {
return LogLevel.Trace;
}
if (typeof this._args.log === 'string') {
const logLevel = this._args.log.toLowerCase();
switch (logLevel) {
case 'trace':
return LogLevel.Trace;
case 'debug':
return LogLevel.Debug;
case 'info':
return LogLevel.Info;
case 'warn':
return LogLevel.Warning;
case 'error':
return LogLevel.Error;
case 'critical':
return LogLevel.Critical;
case 'off':
return LogLevel.Off;
}
}
return LogLevel.Info;
}
get wait(): boolean { return this._args.wait; }
get logExtensionHostCommunication(): boolean { return this._args.logExtensionHostCommunication; }
@ -129,7 +161,14 @@ export class EnvironmentService implements IEnvironmentService {
get disableUpdates(): boolean { return !!this._args['disable-updates']; }
get disableCrashReporter(): boolean { return !!this._args['disable-crash-reporter']; }
constructor(private _args: ParsedArgs, private _execPath: string) { }
constructor(private _args: ParsedArgs, private _execPath: string) {
if (!process.env['VSCODE_LOGS']) {
const key = toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '');
process.env['VSCODE_LOGS'] = path.join(this.userDataPath, 'logs', key);
}
this.logsPath = process.env['VSCODE_LOGS'];
}
}
export function parseExtensionHostPort(args: ParsedArgs, isBuild: boolean): IExtensionHostDebugParams {

View file

@ -281,7 +281,7 @@ export class HistoryMainService implements IHistoryMainService {
try {
app.setJumpList(jumpList);
} catch (error) {
this.logService.info('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors
this.logService.warn('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors
}
}
}

View file

@ -124,7 +124,7 @@ export class LifecycleService implements ILifecycleService {
// before-quit
app.on('before-quit', (e) => {
this.logService.info('Lifecycle#before-quit');
this.logService.trace('Lifecycle#before-quit');
if (!this.quitRequested) {
this._onBeforeQuit.fire(); // only send this if this is the first quit request we have
@ -135,7 +135,7 @@ export class LifecycleService implements ILifecycleService {
// window-all-closed
app.on('window-all-closed', () => {
this.logService.info('Lifecycle#window-all-closed');
this.logService.trace('Lifecycle#window-all-closed');
// Windows/Linux: we quit when all windows have closed
// Mac: we only quit when quit was requested
@ -150,11 +150,11 @@ export class LifecycleService implements ILifecycleService {
// Window Before Closing: Main -> Renderer
window.win.on('close', e => {
const windowId = window.id;
this.logService.info('Lifecycle#window-before-close', windowId);
this.logService.trace('Lifecycle#window-before-close', windowId);
// The window already acknowledged to be closed
if (this.windowToCloseRequest[windowId]) {
this.logService.info('Lifecycle#window-close', windowId);
this.logService.trace('Lifecycle#window-close', windowId);
delete this.windowToCloseRequest[windowId];
@ -183,7 +183,7 @@ export class LifecycleService implements ILifecycleService {
return TPromise.as<boolean>(false);
}
this.logService.info('Lifecycle#unload()', window.id);
this.logService.trace('Lifecycle#unload()', window.id);
const windowUnloadReason = this.quitRequested ? UnloadReason.QUIT : reason;
@ -247,7 +247,7 @@ export class LifecycleService implements ILifecycleService {
* by the user or not.
*/
public quit(fromUpdate?: boolean): TPromise<boolean /* veto */> {
this.logService.info('Lifecycle#quit()');
this.logService.trace('Lifecycle#quit()');
if (!this.pendingQuitPromise) {
this.pendingQuitPromise = new TPromise<boolean>(c => {

View file

@ -12,17 +12,19 @@ import { createDecorator } from 'vs/base/common/decorators';
export const ILogService = createServiceDecorator<ILogService>('logService');
export enum LogLevel {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
CRITICAL
Trace,
Debug,
Info,
Warning,
Error,
Critical,
Off
}
export interface ILogService {
_serviceBrand: any;
setLevel(level: LogLevel): void;
trace(message: string, ...args: any[]): void;
debug(message: string, ...args: any[]): void;
info(message: string, ...args: any[]): void;
@ -34,39 +36,118 @@ export interface ILogService {
export class LegacyLogMainService implements ILogService {
_serviceBrand: any;
private level: LogLevel = LogLevel.Error;
constructor(
processName: string,
@IEnvironmentService private environmentService: IEnvironmentService
) { }
constructor( @IEnvironmentService environmentService: IEnvironmentService) {
this.setLevel(environmentService.logLevel);
}
setLevel(level: LogLevel): void {
this.level = level;
}
trace(message: string, ...args: any[]): void {
// console.log(`\x1b[90m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
}
debug(message: string, ...args: any[]): void {
// console.log(`\x1b[90m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
}
info(message: string, ...args: any[]): void {
if (this.environmentService.verbose) {
if (this.level <= LogLevel.Trace) {
console.log(`\x1b[90m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
}
}
error(message: string, ...args: any[]): void {
console.error(`\x1b[91m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
debug(message: string, ...args: any[]): void {
if (this.level <= LogLevel.Debug) {
console.log(`\x1b[90m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
}
}
info(message: string, ...args: any[]): void {
if (this.level <= LogLevel.Info) {
console.log(`\x1b[90m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
}
}
warn(message: string | Error, ...args: any[]): void {
console.warn(`\x1b[93m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
if (this.level <= LogLevel.Warning) {
console.warn(`\x1b[93m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
}
}
error(message: string, ...args: any[]): void {
if (this.level <= LogLevel.Error) {
console.error(`\x1b[91m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
}
}
critical(message: string, ...args: any[]): void {
// console.log(`\x1b[90m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
if (this.level <= LogLevel.Critical) {
console.error(`\x1b[90m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
}
}
}
export class MultiplexLogService implements ILogService {
_serviceBrand: any;
constructor(private logServices: ILogService[]) { }
setLevel(level: LogLevel): void {
for (const logService of this.logServices) {
logService.setLevel(level);
}
}
trace(message: string, ...args: any[]): void {
for (const logService of this.logServices) {
logService.trace(message, ...args);
}
}
debug(message: string, ...args: any[]): void {
for (const logService of this.logServices) {
logService.debug(message, ...args);
}
}
info(message: string, ...args: any[]): void {
for (const logService of this.logServices) {
logService.info(message, ...args);
}
}
warn(message: string, ...args: any[]): void {
for (const logService of this.logServices) {
logService.warn(message, ...args);
}
}
error(message: string | Error, ...args: any[]): void {
for (const logService of this.logServices) {
logService.error(message, ...args);
}
}
critical(message: string | Error, ...args: any[]): void {
for (const logService of this.logServices) {
logService.critical(message, ...args);
}
}
}
export class NoopLogService implements ILogService {
_serviceBrand: any;
setLevel(level: LogLevel): void { }
trace(message: string, ...args: any[]): void { }
debug(message: string, ...args: any[]): void { }
info(message: string, ...args: any[]): void { }
warn(message: string, ...args: any[]): void { }
error(message: string | Error, ...args: any[]): void { }
critical(message: string | Error, ...args: any[]): void { }
}
let globalLogService: ILogService = new NoopLogService();
export function registerGlobalLogService(logService: ILogService): void {
globalLogService = logService;
}
export function log(level: LogLevel, prefix: string, logFn?: (message: string, ...args: any[]) => string): Function {
return createDecorator((fn, key) => {
// TODO@Joao: load-time log level? return fn;
@ -79,25 +160,15 @@ export function log(level: LogLevel, prefix: string, logFn?: (message: string, .
}
switch (level) {
case LogLevel.TRACE: this.logService.trace(message); break;
case LogLevel.DEBUG: this.logService.debug(message); break;
case LogLevel.INFO: this.logService.info(message); break;
case LogLevel.WARN: this.logService.warn(message); break;
case LogLevel.ERROR: this.logService.error(message); break;
case LogLevel.CRITICAL: this.logService.critical(message); break;
case LogLevel.Trace: globalLogService.trace(message); break;
case LogLevel.Debug: globalLogService.debug(message); break;
case LogLevel.Info: globalLogService.info(message); break;
case LogLevel.Warning: globalLogService.warn(message); break;
case LogLevel.Error: globalLogService.error(message); break;
case LogLevel.Critical: globalLogService.critical(message); break;
}
return fn.apply(this, args);
};
});
}
export class NoopLogService implements ILogService {
_serviceBrand: any;
trace(message: string, ...args: any[]): void { }
debug(message: string, ...args: any[]): void { }
info(message: string, ...args: any[]): void { }
warn(message: string, ...args: any[]): void { }
error(message: string | Error, ...args: any[]): void { }
critical(message: string | Error, ...args: any[]): void { }
}

View file

@ -5,41 +5,102 @@
'use strict';
import { ILogService } from 'vs/platform/log/common/log';
import * as path from 'path';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { RotatingLogger, setAsyncMode } from 'spdlog';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { fromNodeEventEmitter } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { readdir, rimraf } from 'vs/base/node/pfs';
export class SpdLogService implements ILogService {
_serviceBrand: any;
private logger: RotatingLogger;
private disposables: IDisposable[] = [];
private formatRegexp = /{(\d+)}/g;
constructor(
processName: string,
@IEnvironmentService environmentService: IEnvironmentService
@IEnvironmentService private environmentService: IEnvironmentService
) {
// TODO create logger
setAsyncMode(8192, 2000);
const logfilePath = path.join(environmentService.logsPath, `${processName}.log`);
this.logger = new RotatingLogger(processName, logfilePath, 1024 * 1024 * 5, 6);
this.setLevel(environmentService.logLevel);
fromNodeEventEmitter(process, 'exit')(() => this.logger.flush(), null, this.disposables);
}
/**
* Cleans up older logs, while keeping the 10 most recent ones.
*/
async cleanup(): TPromise<void> {
const currentLog = path.basename(this.environmentService.logsPath);
const logsRoot = path.dirname(this.environmentService.logsPath);
const children = await readdir(logsRoot);
const allSessions = children.filter(name => /^\d{8}T\d{6}$/.test(name));
const oldSessions = allSessions.sort().filter((d, i) => d !== currentLog);
const toDelete = oldSessions.slice(0, Math.max(0, oldSessions.length - 9));
await TPromise.join(toDelete.map(name => rimraf(path.join(logsRoot, name))));
}
setLevel(logLevel: LogLevel): void {
this.logger.setLevel(logLevel);
}
// TODO, what about ARGS?
trace(message: string, ...args: any[]): void {
// console.log('TRACE', message, ...args);
this.logger.trace(this.format(message, args));
}
debug(message: string, ...args: any[]): void {
// console.log('DEBUG', message, ...args);
this.logger.debug(this.format(message, args));
}
info(message: string, ...args: any[]): void {
// console.log('INFO', message, ...args);
this.logger.info(this.format(message, args));
}
warn(message: string, ...args: any[]): void {
// console.warn('WARN', message, ...args);
this.logger.warn(this.format(message, args));
}
error(message: string | Error, ...args: any[]): void {
// console.error('ERROR', message, ...args);
error(arg: string | Error, ...args: any[]): void {
const message = arg instanceof Error ? arg.stack : arg;
this.logger.error(this.format(message, args));
}
critical(message: string, ...args: any[]): void {
// console.error('CRITICAL', message, ...args);
this.logger.critical(this.format(message, args));
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
private format(value: string, ...args: any[]): string {
if (args.length) {
value = value.replace(this.formatRegexp, (match, group) => {
let idx = parseInt(group, 10);
return isNaN(idx) || idx < 0 || idx >= args.length ?
match :
this.toStringValue(args[idx]);
});
}
return value;
}
private toStringValue(value: any): string {
if (typeof value === 'object') {
try {
return JSON.stringify(value);
} catch (e) { }
}
return value;
}
}

View file

@ -270,10 +270,10 @@ export class UpdateService implements IUpdateService {
return TPromise.as(null);
}
this.logService.info('update#quitAndInstall(): before lifecycle quit()');
this.logService.trace('update#quitAndInstall(): before lifecycle quit()');
this.lifecycleService.quit(true /* from update */).done(vetod => {
this.logService.info(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`);
this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`);
if (vetod) {
return;
}
@ -282,11 +282,11 @@ export class UpdateService implements IUpdateService {
// we workaround this issue by forcing an explicit flush of the storage data.
// see also https://github.com/Microsoft/vscode/issues/172
if (process.platform === 'darwin') {
this.logService.info('update#quitAndInstall(): calling flushStorageData()');
this.logService.trace('update#quitAndInstall(): calling flushStorageData()');
electron.session.defaultSession.flushStorageData();
}
this.logService.info('update#quitAndInstall(): running raw#quitAndInstall()');
this.logService.trace('update#quitAndInstall(): running raw#quitAndInstall()');
this.raw.quitAndInstall();
});

View file

@ -86,7 +86,7 @@ export class WorkspacesMainService implements IWorkspacesMainService {
folders: toWorkspaceFolders(workspace.folders, URI.file(dirname(path)))
};
} catch (error) {
this.logService.info(error.toString());
this.logService.warn(error.toString());
}
return null;
@ -262,7 +262,7 @@ export class WorkspacesMainService implements IWorkspacesMainService {
try {
delSync(dirname(configPath));
} catch (error) {
this.logService.info(`Unable to delete untitled workspace ${configPath} (${error}).`);
this.logService.warn(`Unable to delete untitled workspace ${configPath} (${error}).`);
}
}
@ -271,7 +271,7 @@ export class WorkspacesMainService implements IWorkspacesMainService {
try {
untitledWorkspacePaths = readdirSync(this.workspacesHome).map(folder => join(this.workspacesHome, folder, UNTITLED_WORKSPACE_NAME));
} catch (error) {
this.logService.info(`Unable to read folders in ${this.workspacesHome} (${error}).`);
this.logService.warn(`Unable to read folders in ${this.workspacesHome} (${error}).`);
}
const untitledWorkspaces: IWorkspaceIdentifier[] = coalesce(untitledWorkspacePaths.map(untitledWorkspacePath => {

View file

@ -48,7 +48,7 @@ suite('WorkspacesMainService', () => {
}
const environmentService = new TestEnvironmentService(parseArgs(process.argv), process.execPath);
const logService = new LegacyLogMainService('test', environmentService);
const logService = new LegacyLogMainService(environmentService);
let service: TestWorkspacesMainService;

View file

@ -57,7 +57,6 @@ import { FileChangeType, FileType } from 'vs/platform/files/common/files';
import { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations';
import { toGlobPattern, toLanguageSelector } from 'vs/workbench/api/node/extHostTypeConverters';
import { ExtensionActivatedByAPI } from 'vs/workbench/api/node/extHostExtensionActivator';
import { ILogService } from 'vs/platform/log/common/log';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
export interface IExtensionApiFactory {
@ -82,8 +81,7 @@ export function createApiFactory(
threadService: ExtHostThreadService,
extHostWorkspace: ExtHostWorkspace,
extHostConfiguration: ExtHostConfiguration,
extensionService: ExtHostExtensionService,
logService: ILogService
extensionService: ExtHostExtensionService
): IExtensionApiFactory {
// Addressable instances
@ -94,7 +92,7 @@ export function createApiFactory(
const extHostDocumentContentProviders = threadService.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(threadService, extHostDocumentsAndEditors));
const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadEditors)));
const extHostEditors = threadService.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(threadService, extHostDocumentsAndEditors));
const extHostCommands = threadService.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(threadService, extHostHeapService, logService));
const extHostCommands = threadService.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(threadService, extHostHeapService));
const extHostTreeViews = threadService.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(threadService.get(MainContext.MainThreadTreeViews), extHostCommands));
threadService.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
const extHostDebugService = threadService.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(threadService, extHostWorkspace));
@ -105,7 +103,7 @@ export function createApiFactory(
const extHostFileSystemEvent = threadService.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService());
const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService, extHostWorkspace, extHostCommands));
const extHostTerminalService = threadService.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(threadService));
const extHostSCM = threadService.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(threadService, extHostCommands, logService));
const extHostSCM = threadService.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(threadService, extHostCommands));
const extHostTask = threadService.set(ExtHostContext.ExtHostTask, new ExtHostTask(threadService, extHostWorkspace));
const extHostWindow = threadService.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(threadService));
threadService.set(ExtHostContext.ExtHostExtensionService, extensionService);

View file

@ -76,6 +76,7 @@ export interface IInitData {
extensions: IExtensionDescription[];
configuration: IConfigurationInitData;
telemetryInfo: ITelemetryInfo;
windowId: number;
args: ParsedArgs;
execPath: string;
}

View file

@ -15,7 +15,7 @@ import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import * as modes from 'vs/editor/common/modes';
import * as vscode from 'vscode';
import { ILogService, log, LogLevel } from 'vs/platform/log/common/log';
import { log, LogLevel } from 'vs/platform/log/common/log';
interface CommandHandler {
callback: Function;
@ -36,9 +36,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
constructor(
mainContext: IMainContext,
heapService: ExtHostHeapService,
// @ts-ignore
@ILogService private logService: ILogService
heapService: ExtHostHeapService
) {
this._proxy = mainContext.get(MainContext.MainThreadCommands);
this._converter = new CommandsConverter(this, heapService);
@ -52,7 +50,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
this._argumentProcessors.push(processor);
}
@log(LogLevel.TRACE, 'ExtHostCommands', (msg, id) => `${msg}(${id})`)
@log(LogLevel.Trace, 'ExtHostCommands', (msg, id) => `${msg}(${id})`)
registerCommand(id: string, callback: <T>(...args: any[]) => T | Thenable<T>, thisArg?: any, description?: ICommandHandlerDescription): extHostTypes.Disposable {
if (!id.trim().length) {
@ -73,7 +71,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
});
}
@log(LogLevel.TRACE, 'ExtHostCommands', (msg, id) => `${msg}(${id})`)
@log(LogLevel.Trace, 'ExtHostCommands', (msg, id) => `${msg}(${id})`)
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
if (this._commands.has(id)) {
@ -138,7 +136,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
}
}
@log(LogLevel.TRACE, 'ExtHostCommands', (msg, filterUnderscoreCommands) => `${msg}(${filterUnderscoreCommands})`)
@log(LogLevel.Trace, 'ExtHostCommands', (msg, filterUnderscoreCommands) => `${msg}(${filterUnderscoreCommands})`)
getCommands(filterUnderscoreCommands: boolean = false): Thenable<string[]> {
return this._proxy.$getCommands().then(result => {
if (filterUnderscoreCommands) {

View file

@ -21,7 +21,6 @@ import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { realpath } from 'fs';
import { TernarySearchTree } from 'vs/base/common/map';
import { Barrier } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
class ExtensionMemento implements IExtensionMemento {
@ -126,8 +125,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
constructor(initData: IInitData,
threadService: ExtHostThreadService,
extHostWorkspace: ExtHostWorkspace,
extHostConfiguration: ExtHostConfiguration,
logService: ILogService
extHostConfiguration: ExtHostConfiguration
) {
this._barrier = new Barrier();
this._registry = new ExtensionDescriptionRegistry(initData.extensions);
@ -139,7 +137,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
this._activator = null;
// initialize API first (i.e. do not release barrier until the API is initialized)
const apiFactory = createApiFactory(initData, threadService, extHostWorkspace, extHostConfiguration, this, logService);
const apiFactory = createApiFactory(initData, threadService, extHostWorkspace, extHostConfiguration, this);
initializeExtensionApi(this, apiFactory).then(() => {

View file

@ -17,7 +17,7 @@ import { sortedDiff } from 'vs/base/common/arrays';
import { comparePaths } from 'vs/base/common/comparers';
import * as vscode from 'vscode';
import { ISplice } from 'vs/base/common/sequence';
import { log, LogLevel, ILogService } from 'vs/platform/log/common/log';
import { log, LogLevel } from 'vs/platform/log/common/log';
type ProviderHandle = number;
type GroupHandle = number;
@ -444,9 +444,7 @@ export class ExtHostSCM {
constructor(
mainContext: IMainContext,
private _commands: ExtHostCommands,
// @ts-ignore
@ILogService private logService: ILogService
private _commands: ExtHostCommands
) {
this._proxy = mainContext.get(MainContext.MainThreadSCM);
@ -489,7 +487,7 @@ export class ExtHostSCM {
});
}
@log(LogLevel.TRACE, 'ExtHostSCM', (msg, extension, id, label, rootUri) => `${msg}(${extension.id}, ${id}, ${label}, ${rootUri})`)
@log(LogLevel.Trace, 'ExtHostSCM', (msg, extension, id, label, rootUri) => `${msg}(${extension.id}, ${id}, ${label}, ${rootUri})`)
createSourceControl(extension: IExtensionDescription, id: string, label: string, rootUri: vscode.Uri | undefined): vscode.SourceControl {
const handle = ExtHostSCM._handlePool++;
const sourceControl = new ExtHostSourceControl(this._proxy, this._commands, id, label, rootUri);
@ -503,7 +501,7 @@ export class ExtHostSCM {
}
// Deprecated
@log(LogLevel.TRACE, 'ExtHostSCM', (msg, extension) => `${msg}(${extension.id})`)
@log(LogLevel.Trace, 'ExtHostSCM', (msg, extension) => `${msg}(${extension.id})`)
getLastInputBox(extension: IExtensionDescription): ExtHostSCMInputBox {
const sourceControls = this._sourceControlsByExtension.get(extension.id);
const sourceControl = sourceControls && sourceControls[sourceControls.length - 1];
@ -512,7 +510,7 @@ export class ExtHostSCM {
return inputBox;
}
@log(LogLevel.TRACE, 'ExtHostSCM', (msg, handle, uri) => `${msg}(${handle}, ${uri})`)
@log(LogLevel.Trace, 'ExtHostSCM', (msg, handle, uri) => `${msg}(${handle}, ${uri})`)
$provideOriginalResource(sourceControlHandle: number, uri: URI): TPromise<URI> {
const sourceControl = this._sourceControls.get(sourceControlHandle);
@ -526,7 +524,7 @@ export class ExtHostSCM {
});
}
@log(LogLevel.TRACE, 'ExtHostSCM', (msg, handle) => `${msg}(${handle})`)
@log(LogLevel.Trace, 'ExtHostSCM', (msg, handle) => `${msg}(${handle})`)
$onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise<void> {
const sourceControl = this._sourceControls.get(sourceControlHandle);
@ -538,7 +536,7 @@ export class ExtHostSCM {
return TPromise.as(null);
}
@log(LogLevel.TRACE, 'ExtHostSCM', (msg, h1, h2, h3) => `${msg}(${h1}, ${h2}, ${h3})`)
@log(LogLevel.Trace, 'ExtHostSCM', (msg, h1, h2, h3) => `${msg}(${h1}, ${h2}, ${h3})`)
async $executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): TPromise<void> {
const sourceControl = this._sourceControls.get(sourceControlHandle);

View file

@ -25,7 +25,7 @@ import { IExtensionManagementService, LocalExtensionType, ILocalExtension, IExte
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import paths = require('vs/base/common/paths');
import { isMacintosh, isLinux, language } from 'vs/base/common/platform';
import { IQuickOpenService, IFilePickOpenEntry, ISeparator, IPickOpenAction, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen';
import { IQuickOpenService, IFilePickOpenEntry, ISeparator, IPickOpenAction, IPickOpenItem, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
import * as browser from 'vs/base/browser/browser';
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
import { IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
@ -46,6 +46,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IExtensionService, ActivationTimes } from 'vs/platform/extensions/common/extensions';
import { getEntries } from 'vs/base/common/performance';
import { IEditor } from 'vs/platform/editor/common/editor';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
// --- actions
@ -1683,3 +1684,81 @@ export class ConfigureLocaleAction extends Action {
});
}
}
export class OpenLogsFolderAction extends Action {
static ID = 'workbench.action.openLogsFolder';
static LABEL = nls.localize('openLogsFolder', "Open Logs Folder");
constructor(id: string, label: string,
@IEnvironmentService private environmentService: IEnvironmentService,
@IWindowsService private windowsService: IWindowsService,
) {
super(id, label);
}
run(): TPromise<void> {
return this.windowsService.showItemInFolder(paths.join(this.environmentService.logsPath, 'main.log'));
}
}
export class ShowLogsAction extends Action {
static ID = 'workbench.action.showLogs';
static LABEL = nls.localize('showLogs', "Show Logs...");
constructor(id: string, label: string,
@IEnvironmentService private environmentService: IEnvironmentService,
@IWindowService private windowService: IWindowService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IQuickOpenService private quickOpenService: IQuickOpenService
) {
super(id, label);
}
run(): TPromise<void> {
const entries: IPickOpenEntry[] = [
{ id: 'main', label: nls.localize('mainProcess', "Main"), run: () => this.editorService.openEditor({ resource: URI.file(paths.join(this.environmentService.logsPath, 'main.log')) }) },
{ id: 'shared', label: nls.localize('sharedProcess', "Shared"), run: () => this.editorService.openEditor({ resource: URI.file(paths.join(this.environmentService.logsPath, 'sharedprocess.log')) }) },
{ id: 'renderer', label: nls.localize('rendererProcess', "Renderer"), run: () => this.editorService.openEditor({ resource: URI.file(paths.join(this.environmentService.logsPath, `renderer${this.windowService.getCurrentWindowId()}.log`)) }) },
{ id: 'extenshionHost', label: nls.localize('extensionHost', "Extension Host"), run: () => this.editorService.openEditor({ resource: URI.file(paths.join(this.environmentService.logsPath, `exthost${this.windowService.getCurrentWindowId()}.log`)) }) }
];
return this.quickOpenService.pick(entries, { placeHolder: nls.localize('selectProcess', "Select process") }).then(entry => {
if (entry) {
entry.run(null);
}
});
}
}
export class SetLogLevelAction extends Action {
static ID = 'workbench.action.setLogLevel';
static LABEL = nls.localize('setLogLevel', "Set Log Level");
constructor(id: string, label: string,
@IQuickOpenService private quickOpenService: IQuickOpenService,
@ILogService private logService: ILogService
) {
super(id, label);
}
run(): TPromise<void> {
const entries = [
{ label: nls.localize('trace', "Trace"), level: LogLevel.Trace },
{ label: nls.localize('debug', "Debug"), level: LogLevel.Debug },
{ label: nls.localize('info', "Info"), level: LogLevel.Info },
{ label: nls.localize('warn', "Warning"), level: LogLevel.Warning },
{ label: nls.localize('err', "Error"), level: LogLevel.Error },
{ label: nls.localize('critical', "Critical"), level: LogLevel.Critical },
{ label: nls.localize('off', "Off"), level: LogLevel.Off }
];
return this.quickOpenService.pick(entries, { placeHolder: nls.localize('selectProcess', "Select process") }).then(entry => {
if (entry) {
this.logService.setLevel(entry.level);
}
});
}
}

View file

@ -14,7 +14,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, ConfigureLocaleAction } from 'vs/workbench/electron-browser/actions';
import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, ConfigureLocaleAction, ShowLogsAction, OpenLogsFolderAction, SetLogLevelAction } from 'vs/workbench/electron-browser/actions';
import { MessagesVisibleContext } from 'vs/workbench/electron-browser/workbench';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { registerCommands } from 'vs/workbench/electron-browser/commands';
@ -36,6 +36,9 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NewWin
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseCurrentWindowAction, CloseCurrentWindowAction.ID, CloseCurrentWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }), 'Close Window');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL, { primary: null, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickSwitchWindow, QuickSwitchWindow.ID, QuickSwitchWindow.LABEL), 'Quick Switch Window...');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowLogsAction, ShowLogsAction.ID, ShowLogsAction.LABEL), 'Show Logs...');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Open Log Folder');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.LABEL), 'Set Log Level');
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory);

View file

@ -39,9 +39,10 @@ import { URLChannelClient } from 'vs/platform/url/common/urlIpc';
import { IURLService } from 'vs/platform/url/common/url';
import { WorkspacesChannelClient } from 'vs/platform/workspaces/common/workspacesIpc';
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import fs = require('fs');
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { registerGlobalLogService } from 'vs/platform/log/common/log';
gracefulFs.gracefulify(fs); // enable gracefulFs
const currentWindowId = remote.getCurrentWindow().id;
@ -73,12 +74,15 @@ function openWorkbench(configuration: IWindowConfiguration): TPromise<void> {
const mainServices = createMainProcessServices(mainProcessClient);
const environmentService = new EnvironmentService(configuration, configuration.execPath);
const logService = new SpdLogService('renderer', environmentService);
const logService = new SpdLogService(`renderer${currentWindowId}`, environmentService);
registerGlobalLogService(logService);
logService.info('openWorkbench', JSON.stringify(configuration));
// Since the configuration service is one of the core services that is used in so many places, we initialize it
// right before startup of the workbench shell to have its data ready for consumers
return createAndInitializeWorkspaceService(configuration, environmentService).then(workspaceService => {
const timerService = new TimerService((<any>window).MonacoEnvironment.timers as IInitData, workspaceService.getWorkbenchState() === WorkbenchState.EMPTY);
const storageService = createStorageService(workspaceService, environmentService);

View file

@ -24,6 +24,7 @@ import * as glob from 'vs/base/common/glob';
import { ExtensionActivatedByEvent } from 'vs/workbench/api/node/extHostExtensionActivator';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { registerGlobalLogService } from 'vs/platform/log/common/log';
// const nativeExit = process.exit.bind(process);
function patchProcess(allowExit: boolean) {
@ -87,10 +88,13 @@ export class ExtensionHostMain {
const threadService = new ExtHostThreadService(rpcProtocol);
const extHostWorkspace = new ExtHostWorkspace(threadService, initData.workspace);
const environmentService = new EnvironmentService(initData.args, initData.execPath);
const logService = new SpdLogService('exthost', environmentService);
const logService = new SpdLogService(`exthost${initData.windowId}`, environmentService);
registerGlobalLogService(logService);
logService.info('main {0}', initData);
this._extHostConfiguration = new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), extHostWorkspace, initData.configuration);
this._extensionService = new ExtHostExtensionService(initData, threadService, extHostWorkspace, this._extHostConfiguration, logService);
this._extensionService = new ExtHostExtensionService(initData, threadService, extHostWorkspace, this._extHostConfiguration);
// error forwarding and stack trace scanning
const extensionErrors = new WeakMap<Error, IExtensionDescription>();

View file

@ -367,7 +367,8 @@ export class ExtensionHostProcessWorker {
configuration: !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment ? { ...configurationData, configurationScopes: getScopes(this._configurationService.keys().default) } : configurationData,
telemetryInfo,
args: this._environmentService.args,
execPath: this._environmentService.execPath
execPath: this._environmentService.execPath,
windowId: this._windowService.getCurrentWindowId()
};
return r;
});

View file

@ -8,7 +8,7 @@
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event';
import { ISCMService, ISCMProvider, ISCMInput, ISCMRepository } from './scm';
import { log, LogLevel, ILogService } from 'vs/platform/log/common/log';
import { log, LogLevel } from 'vs/platform/log/common/log';
class SCMInput implements ISCMInput {
@ -77,12 +77,7 @@ export class SCMService implements ISCMService {
private _onDidRemoveProvider = new Emitter<ISCMRepository>();
get onDidRemoveRepository(): Event<ISCMRepository> { return this._onDidRemoveProvider.event; }
constructor(
// @ts-ignore
@ILogService private logService: ILogService
) { }
@log(LogLevel.INFO, 'SCMService')
@log(LogLevel.Info, 'SCMService')
registerSCMProvider(provider: ISCMProvider): ISCMRepository {
if (this._providerIds.has(provider.id)) {
throw new Error(`SCM Provider ${provider.id} already exists.`);

View file

@ -32,7 +32,6 @@ import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import * as vscode from 'vscode';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import 'vs/workbench/parts/search/electron-browser/search.contribution';
import { NoopLogService } from 'vs/platform/log/common/log';
const defaultSelector = { scheme: 'far' };
const model: EditorCommon.IModel = EditorModel.createFromString(
@ -113,9 +112,8 @@ suite('ExtHostLanguageFeatureCommands', function () {
threadService.set(ExtHostContext.ExtHostDocuments, extHostDocuments);
const heapService = new ExtHostHeapService();
const logService = new NoopLogService();
commands = new ExtHostCommands(threadService, heapService, logService);
commands = new ExtHostCommands(threadService, heapService);
threadService.set(ExtHostContext.ExtHostCommands, commands);
threadService.setTestInstance(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, threadService));
ExtHostApiCommands.register(commands);

View file

@ -12,7 +12,6 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { OneGetThreadService } from './testThreadService';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { NoopLogService } from 'vs/platform/log/common/log';
suite('ExtHostCommands', function () {
@ -30,7 +29,7 @@ suite('ExtHostCommands', function () {
}
};
const commands = new ExtHostCommands(OneGetThreadService(shape), undefined, new NoopLogService());
const commands = new ExtHostCommands(OneGetThreadService(shape), undefined);
commands.registerCommand('foo', (): any => { }).dispose();
assert.equal(lastUnregister, 'foo');
assert.equal(CommandsRegistry.getCommand('foo'), undefined);
@ -51,7 +50,7 @@ suite('ExtHostCommands', function () {
}
};
const commands = new ExtHostCommands(OneGetThreadService(shape), undefined, new NoopLogService());
const commands = new ExtHostCommands(OneGetThreadService(shape), undefined);
const reg = commands.registerCommand('foo', (): any => { });
reg.dispose();
reg.dispose();

View file

@ -44,7 +44,6 @@ import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
import * as vscode from 'vscode';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { NoopLogService } from 'vs/platform/log/common/log';
const defaultSelector = { scheme: 'far' };
const model: EditorCommon.IModel = EditorModel.createFromString(
@ -103,7 +102,7 @@ suite('ExtHostLanguageFeatures', function () {
const heapService = new ExtHostHeapService();
const commands = new ExtHostCommands(threadService, heapService, new NoopLogService());
const commands = new ExtHostCommands(threadService, heapService);
threadService.set(ExtHostContext.ExtHostCommands, commands);
threadService.setTestInstance(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, threadService));

View file

@ -17,7 +17,6 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
import { MainThreadCommands } from 'vs/workbench/api/electron-browser/mainThreadCommands';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { NoopLogService } from 'vs/platform/log/common/log';
import { TPromise } from 'vs/base/common/winjs.base';
import { TreeItemCollapsibleState, ITreeItem } from 'vs/workbench/common/views';
@ -66,7 +65,7 @@ suite('ExtHostTreeView', function () {
threadService.setTestInstance(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, threadService));
target = new RecordingShape();
testObject = new ExtHostTreeViews(target, new ExtHostCommands(threadService, new ExtHostHeapService(), new NoopLogService()));
testObject = new ExtHostTreeViews(target, new ExtHostCommands(threadService, new ExtHostHeapService()));
onDidChangeTreeData = new Emitter<string>();
testObject.registerTreeDataProvider('testDataProvider', aTreeDataProvider());

View file

@ -387,7 +387,7 @@ binaryextensions@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-1.0.1.tgz#1e637488b35b58bda5f4774bf96a5212a8c90755"
bindings@^1.2.1:
bindings@^1.2.1, bindings@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7"
@ -3738,6 +3738,10 @@ nan@^2.1.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46"
nan@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a"
native-keymap@1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/native-keymap/-/native-keymap-1.2.5.tgz#1035a9417b9a9340cf8097763a43c76d588165a5"
@ -5034,6 +5038,14 @@ sparkles@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3"
spdlog@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.2.1.tgz#1a9de952ccffe9b9227dd20306aca7e428621fa1"
dependencies:
bindings "^1.3.0"
mkdirp "^0.5.1"
nan "^2.8.0"
spdx-correct@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"