UNPKG

@sussudio/platform

Version:

Internal APIs for VS Code's service injection the base services.

471 lines (470 loc) 12.1 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { toErrorMessage } from '@sussudio/base/common/errorMessage.mjs'; import { Emitter, Event } from '@sussudio/base/common/event.mjs'; import { Disposable } from '@sussudio/base/common/lifecycle.mjs'; import { ResourceMap } from '@sussudio/base/common/map.mjs'; import { isWindows } from '@sussudio/base/common/platform.mjs'; import { URI } from '@sussudio/base/common/uri.mjs'; import { createDecorator } from '../../instantiation/common/instantiation.mjs'; export const ILogService = createDecorator('logService'); export const ILoggerService = createDecorator('loggerService'); function now() { return new Date().toISOString(); } export var LogLevel; (function (LogLevel) { LogLevel[(LogLevel['Off'] = 0)] = 'Off'; LogLevel[(LogLevel['Trace'] = 1)] = 'Trace'; LogLevel[(LogLevel['Debug'] = 2)] = 'Debug'; LogLevel[(LogLevel['Info'] = 3)] = 'Info'; LogLevel[(LogLevel['Warning'] = 4)] = 'Warning'; LogLevel[(LogLevel['Error'] = 5)] = 'Error'; })(LogLevel || (LogLevel = {})); export const DEFAULT_LOG_LEVEL = LogLevel.Info; export function log(logger, level, message) { switch (level) { case LogLevel.Trace: logger.trace(message); break; case LogLevel.Debug: logger.debug(message); break; case LogLevel.Info: logger.info(message); break; case LogLevel.Warning: logger.warn(message); break; case LogLevel.Error: logger.error(message); break; case LogLevel.Off: /* do nothing */ break; default: throw new Error(`Invalid log level ${level}`); } } export function format(args) { let result = ''; for (let i = 0; i < args.length; i++) { let a = args[i]; if (typeof a === 'object') { try { a = JSON.stringify(a); } catch (e) {} } result += (i > 0 ? ' ' : '') + a; } return result; } export class AbstractLogger extends Disposable { level = DEFAULT_LOG_LEVEL; _onDidChangeLogLevel = this._register(new Emitter()); onDidChangeLogLevel = this._onDidChangeLogLevel.event; setLevel(level) { if (this.level !== level) { this.level = level; this._onDidChangeLogLevel.fire(this.level); } } getLevel() { return this.level; } checkLogLevel(level) { return this.level !== LogLevel.Off && this.level <= level; } } export class AbstractMessageLogger extends AbstractLogger { logAlways; constructor(logAlways) { super(); this.logAlways = logAlways; } checkLogLevel(level) { return this.logAlways || super.checkLogLevel(level); } trace(message, ...args) { if (this.checkLogLevel(LogLevel.Trace)) { this.log(LogLevel.Trace, format([message, ...args])); } } debug(message, ...args) { if (this.checkLogLevel(LogLevel.Debug)) { this.log(LogLevel.Debug, format([message, ...args])); } } info(message, ...args) { if (this.checkLogLevel(LogLevel.Info)) { this.log(LogLevel.Info, format([message, ...args])); } } warn(message, ...args) { if (this.checkLogLevel(LogLevel.Warning)) { this.log(LogLevel.Warning, format([message, ...args])); } } error(message, ...args) { if (this.checkLogLevel(LogLevel.Error)) { if (message instanceof Error) { const array = Array.prototype.slice.call(arguments); array[0] = message.stack; this.log(LogLevel.Error, format(array)); } else { this.log(LogLevel.Error, format([message, ...args])); } } } flush() {} } export class ConsoleMainLogger extends AbstractLogger { useColors; constructor(logLevel = DEFAULT_LOG_LEVEL) { super(); this.setLevel(logLevel); this.useColors = !isWindows; } trace(message, ...args) { if (this.checkLogLevel(LogLevel.Trace)) { if (this.useColors) { console.log(`\x1b[90m[main ${now()}]\x1b[0m`, message, ...args); } else { console.log(`[main ${now()}]`, message, ...args); } } } debug(message, ...args) { if (this.checkLogLevel(LogLevel.Debug)) { if (this.useColors) { console.log(`\x1b[90m[main ${now()}]\x1b[0m`, message, ...args); } else { console.log(`[main ${now()}]`, message, ...args); } } } info(message, ...args) { if (this.checkLogLevel(LogLevel.Info)) { if (this.useColors) { console.log(`\x1b[90m[main ${now()}]\x1b[0m`, message, ...args); } else { console.log(`[main ${now()}]`, message, ...args); } } } warn(message, ...args) { if (this.checkLogLevel(LogLevel.Warning)) { if (this.useColors) { console.warn(`\x1b[93m[main ${now()}]\x1b[0m`, message, ...args); } else { console.warn(`[main ${now()}]`, message, ...args); } } } error(message, ...args) { if (this.checkLogLevel(LogLevel.Error)) { if (this.useColors) { console.error(`\x1b[91m[main ${now()}]\x1b[0m`, message, ...args); } else { console.error(`[main ${now()}]`, message, ...args); } } } dispose() { // noop } flush() { // noop } } export class ConsoleLogger extends AbstractLogger { constructor(logLevel = DEFAULT_LOG_LEVEL) { super(); this.setLevel(logLevel); } trace(message, ...args) { if (this.checkLogLevel(LogLevel.Trace)) { console.log('%cTRACE', 'color: #888', message, ...args); } } debug(message, ...args) { if (this.checkLogLevel(LogLevel.Debug)) { console.log('%cDEBUG', 'background: #eee; color: #888', message, ...args); } } info(message, ...args) { if (this.checkLogLevel(LogLevel.Info)) { console.log('%c INFO', 'color: #33f', message, ...args); } } warn(message, ...args) { if (this.checkLogLevel(LogLevel.Warning)) { console.log('%c WARN', 'color: #993', message, ...args); } } error(message, ...args) { if (this.checkLogLevel(LogLevel.Error)) { console.log('%c ERR', 'color: #f33', message, ...args); } } dispose() { // noop } flush() { // noop } } export class AdapterLogger extends AbstractLogger { adapter; constructor(adapter, logLevel = DEFAULT_LOG_LEVEL) { super(); this.adapter = adapter; this.setLevel(logLevel); } trace(message, ...args) { if (this.checkLogLevel(LogLevel.Trace)) { this.adapter.log(LogLevel.Trace, [this.extractMessage(message), ...args]); } } debug(message, ...args) { if (this.checkLogLevel(LogLevel.Debug)) { this.adapter.log(LogLevel.Debug, [this.extractMessage(message), ...args]); } } info(message, ...args) { if (this.checkLogLevel(LogLevel.Info)) { this.adapter.log(LogLevel.Info, [this.extractMessage(message), ...args]); } } warn(message, ...args) { if (this.checkLogLevel(LogLevel.Warning)) { this.adapter.log(LogLevel.Warning, [this.extractMessage(message), ...args]); } } error(message, ...args) { if (this.checkLogLevel(LogLevel.Error)) { this.adapter.log(LogLevel.Error, [this.extractMessage(message), ...args]); } } extractMessage(msg) { if (typeof msg === 'string') { return msg; } return toErrorMessage(msg, this.checkLogLevel(LogLevel.Trace)); } dispose() { // noop } flush() { // noop } } export class MultiplexLogService extends AbstractLogger { logServices; constructor(logServices) { super(); this.logServices = logServices; if (logServices.length) { this.setLevel(logServices[0].getLevel()); } } setLevel(level) { for (const logService of this.logServices) { logService.setLevel(level); } super.setLevel(level); } trace(message, ...args) { for (const logService of this.logServices) { logService.trace(message, ...args); } } debug(message, ...args) { for (const logService of this.logServices) { logService.debug(message, ...args); } } info(message, ...args) { for (const logService of this.logServices) { logService.info(message, ...args); } } warn(message, ...args) { for (const logService of this.logServices) { logService.warn(message, ...args); } } error(message, ...args) { for (const logService of this.logServices) { logService.error(message, ...args); } } flush() { for (const logService of this.logServices) { logService.flush(); } } dispose() { for (const logService of this.logServices) { logService.dispose(); } } } export class LogService extends Disposable { logger; constructor(logger) { super(); this.logger = logger; this._register(logger); } get onDidChangeLogLevel() { return this.logger.onDidChangeLogLevel; } setLevel(level) { this.logger.setLevel(level); } getLevel() { return this.logger.getLevel(); } trace(message, ...args) { this.logger.trace(message, ...args); } debug(message, ...args) { this.logger.debug(message, ...args); } info(message, ...args) { this.logger.info(message, ...args); } warn(message, ...args) { this.logger.warn(message, ...args); } error(message, ...args) { this.logger.error(message, ...args); } flush() { this.logger.flush(); } } export class AbstractLoggerService extends Disposable { logLevel; loggerItems = new ResourceMap(); constructor(logLevel, onDidChangeLogLevel) { super(); this.logLevel = logLevel; this._register(onDidChangeLogLevel((logLevel) => this.setLevel(logLevel))); } getLoggers() { return [...this.loggerItems.values()].map(({ logger }) => logger); } getLogger(resource) { return this.loggerItems.get(resource)?.logger; } createLogger(resource, options, logLevel) { let logger = this.loggerItems.get(resource)?.logger; if (!logger) { logLevel = options?.always ? LogLevel.Trace : logLevel; logger = this.doCreateLogger(resource, logLevel ?? this.logLevel, options); this.loggerItems.set(resource, { logger, logLevel }); } return logger; } setLevel(arg1, arg2) { const resource = URI.isUri(arg1) ? arg1 : undefined; const logLevel = resource ? arg2 : arg1; if (resource) { const logger = this.loggerItems.get(resource); if (logger && logger.logLevel !== logLevel) { logger.logLevel = logLevel; logger.logger.setLevel(logLevel); } } else { this.logLevel = logLevel; this.loggerItems.forEach(({ logLevel, logger }) => { if (logLevel === undefined) { logger.setLevel(this.logLevel); } }); } } getLogLevel(resource) { const logger = this.loggerItems.get(resource); return logger?.logLevel; } dispose() { this.loggerItems.forEach(({ logger }) => logger.dispose()); this.loggerItems.clear(); super.dispose(); } } export class NullLogger { onDidChangeLogLevel = new Emitter().event; setLevel(level) {} getLevel() { return LogLevel.Info; } trace(message, ...args) {} debug(message, ...args) {} info(message, ...args) {} warn(message, ...args) {} error(message, ...args) {} critical(message, ...args) {} dispose() {} flush() {} } export class NullLogService extends NullLogger {} export class NullLoggerService extends AbstractLoggerService { constructor() { super(LogLevel.Info, Event.None); } doCreateLogger(resource, logLevel, options) { return new NullLogger(); } } export function getLogLevel(environmentService) { if (environmentService.verbose) { return LogLevel.Trace; } if (typeof environmentService.logLevel === 'string') { const logLevel = parseLogLevel(environmentService.logLevel.toLowerCase()); if (logLevel !== undefined) { return logLevel; } } return DEFAULT_LOG_LEVEL; } export function LogLevelToString(logLevel) { switch (logLevel) { case LogLevel.Trace: return 'trace'; case LogLevel.Debug: return 'debug'; case LogLevel.Info: return 'info'; case LogLevel.Warning: return 'warn'; case LogLevel.Error: return 'error'; case LogLevel.Off: return 'off'; } } export function parseLogLevel(logLevel) { 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.Error; case 'off': return LogLevel.Off; } return undefined; }