diff --git a/src/annotations/gutterBlameAnnotationProvider.ts b/src/annotations/gutterBlameAnnotationProvider.ts index 2aa7c85..ef8df7d 100644 --- a/src/annotations/gutterBlameAnnotationProvider.ts +++ b/src/annotations/gutterBlameAnnotationProvider.ts @@ -8,8 +8,9 @@ import type { CommitFormatOptions } from '../git/formatters/commitFormatter'; import { CommitFormatter } from '../git/formatters/commitFormatter'; import type { GitBlame } from '../git/models/blame'; import type { GitCommit } from '../git/models/commit'; +import { getLogScope } from '../logScope'; import { filterMap } from '../system/array'; -import { getLogScope, log } from '../system/decorators/log'; +import { log } from '../system/decorators/log'; import { first } from '../system/iterable'; import { Stopwatch } from '../system/stopwatch'; import type { TokenOptions } from '../system/string'; diff --git a/src/annotations/gutterChangesAnnotationProvider.ts b/src/annotations/gutterChangesAnnotationProvider.ts index 4a74428..c68f53e 100644 --- a/src/annotations/gutterChangesAnnotationProvider.ts +++ b/src/annotations/gutterChangesAnnotationProvider.ts @@ -12,7 +12,8 @@ import type { Container } from '../container'; import type { GitCommit } from '../git/models/commit'; import type { GitDiff } from '../git/models/diff'; import { localChangesMessage } from '../hovers/hovers'; -import { getLogScope, log } from '../system/decorators/log'; +import { getLogScope } from '../logScope'; +import { log } from '../system/decorators/log'; import { Stopwatch } from '../system/stopwatch'; import type { GitDocumentState, TrackedDocument } from '../trackers/gitDocumentTracker'; import type { AnnotationContext } from './annotationProvider'; diff --git a/src/annotations/gutterHeatmapBlameAnnotationProvider.ts b/src/annotations/gutterHeatmapBlameAnnotationProvider.ts index 1be8007..b8c0dd0 100644 --- a/src/annotations/gutterHeatmapBlameAnnotationProvider.ts +++ b/src/annotations/gutterHeatmapBlameAnnotationProvider.ts @@ -3,7 +3,8 @@ import { Range } from 'vscode'; import { FileAnnotationType } from '../configuration'; import type { Container } from '../container'; import type { GitCommit } from '../git/models/commit'; -import { getLogScope, log } from '../system/decorators/log'; +import { getLogScope } from '../logScope'; +import { log } from '../system/decorators/log'; import { Stopwatch } from '../system/stopwatch'; import type { GitDocumentState } from '../trackers/gitDocumentTracker'; import type { TrackedDocument } from '../trackers/trackedDocument'; diff --git a/src/annotations/lineAnnotationController.ts b/src/annotations/lineAnnotationController.ts index fd76f2f..97ad86e 100644 --- a/src/annotations/lineAnnotationController.ts +++ b/src/annotations/lineAnnotationController.ts @@ -13,9 +13,10 @@ import { CommitFormatter } from '../git/formatters/commitFormatter'; import type { GitCommit } from '../git/models/commit'; import type { PullRequest } from '../git/models/pullRequest'; import { RichRemoteProviders } from '../git/remotes/remoteProviderConnections'; -import type { LogScope } from '../logger'; import { Logger } from '../logger'; -import { debug, getLogScope, log } from '../system/decorators/log'; +import type { LogScope } from '../logScope'; +import { getLogScope } from '../logScope'; +import { debug, log } from '../system/decorators/log'; import { once } from '../system/event'; import { count, every, filter } from '../system/iterable'; import type { PromiseCancelledErrorWithId } from '../system/promise'; diff --git a/src/commands/switchMode.ts b/src/commands/switchMode.ts index ac2a7fb..865d43d 100644 --- a/src/commands/switchMode.ts +++ b/src/commands/switchMode.ts @@ -2,9 +2,10 @@ import { ConfigurationTarget } from 'vscode'; import { configuration } from '../configuration'; import { Commands } from '../constants'; import type { Container } from '../container'; +import { getLogScope } from '../logScope'; import { ModePicker } from '../quickpicks/modePicker'; import { command } from '../system/command'; -import { getLogScope, log } from '../system/decorators/log'; +import { log } from '../system/decorators/log'; import { Command } from './base'; @command() diff --git a/src/config.ts b/src/config.ts index d5f1d14..284b417 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,3 +1,4 @@ +import { LogLevel } from './constants'; import type { DateTimeFormat } from './system/date'; export interface Config { @@ -784,3 +785,18 @@ export interface ViewsFilesConfig { layout: ViewFilesLayout; threshold: number; } + +export function fromOutputLevel(level: LogLevel | OutputLevel): LogLevel { + switch (level) { + case OutputLevel.Silent: + return LogLevel.Off; + case OutputLevel.Errors: + return LogLevel.Error; + case OutputLevel.Verbose: + return LogLevel.Info; + case OutputLevel.Debug: + return LogLevel.Debug; + default: + return level; + } +} diff --git a/src/constants.ts b/src/constants.ts index 5c5478c..42a571e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,4 +1,6 @@ export const quickPickTitleMaxChars = 80; +export const slowCallWarningThreshold = 500; + export const ImageMimetypes: Record = { '.png': 'image/png', '.gif': 'image/gif', @@ -399,6 +401,14 @@ export const enum GlyphChars { ZeroWidthSpace = '\u200b', } +export const enum LogLevel { + Off = 'off', + Error = 'error', + Warn = 'warn', + Info = 'info', + Debug = 'debug', +} + export const enum Schemes { DebugConsole = 'debug', File = 'file', diff --git a/src/container.ts b/src/container.ts index 997f912..30884db 100644 --- a/src/container.ts +++ b/src/container.ts @@ -9,7 +9,7 @@ import { setDefaultGravatarsStyle } from './avatars'; import { GitCodeLensController } from './codelens/codeLensController'; import type { ToggleFileAnnotationCommandArgs } from './commands'; import type { FileAnnotationType, ModeConfig } from './configuration'; -import { AnnotationsToggleMode, configuration, DateSource, DateStyle } from './configuration'; +import { AnnotationsToggleMode, configuration, DateSource, DateStyle, fromOutputLevel } from './configuration'; import { Commands } from './constants'; import { EventBus } from './eventBus'; import { GitFileSystemProvider } from './git/fsProvider'; @@ -259,7 +259,7 @@ export class Container { this._mode = undefined; if (configuration.changed(e, 'outputLevel')) { - Logger.logLevel = configuration.get('outputLevel'); + Logger.logLevel = fromOutputLevel(configuration.get('outputLevel')); } if (configuration.changed(e, 'defaultGravatarsStyle')) { diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index 948221b..866111a 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -1,10 +1,10 @@ import type { ChildProcess, SpawnOptions } from 'child_process'; import { spawn } from 'child_process'; import * as process from 'process'; -import type { CancellationToken } from 'vscode'; +import type { CancellationToken, OutputChannel } from 'vscode'; import { Uri, window, workspace } from 'vscode'; import { hrtime } from '@env/hrtime'; -import { GlyphChars } from '../../../constants'; +import { GlyphChars, LogLevel, slowCallWarningThreshold } from '../../../constants'; import type { GitCommandOptions, GitSpawnOptions } from '../../../git/commandOptions'; import { GitErrorHandling } from '../../../git/commandOptions'; import type { GitDiffFilter } from '../../../git/models/diff'; @@ -25,6 +25,7 @@ import { fsExists, run, RunError } from './shell'; const emptyArray = Object.freeze([]) as unknown as any[]; const emptyObj = Object.freeze({}); +const emptyStr = ''; const gitBranchDefaultConfigs = Object.freeze(['-c', 'color.branch=false']); const gitDiffDefaultConfigs = Object.freeze(['-c', 'color.diff=false']); @@ -186,7 +187,7 @@ export class Git { this.pendingCommands.delete(command); const duration = getDurationMilliseconds(start); - const slow = duration > Logger.slowCallWarningThreshold; + const slow = duration > slowCallWarningThreshold; const status = slow || waiting ? ` (${slow ? `slow${waiting ? ', waiting' : ''}` : ''}${waiting ? 'waiting' : ''})` @@ -205,7 +206,7 @@ export class Git { } else { Logger.log(`[GIT ] ${gitCommand} ${GlyphChars.Dot} ${duration} ms${status}`); } - Logger.logGitCommand( + this.logGitCommand( `${gitCommand}${exception != null ? ` ${GlyphChars.Dot} FAILED` : ''}${waiting ? ' (waited)' : ''}`, duration, exception, @@ -266,7 +267,7 @@ export class Git { proc.once('error', e => (exception = e)); proc.once('exit', () => { const duration = getDurationMilliseconds(start); - const slow = duration > Logger.slowCallWarningThreshold; + const slow = duration > slowCallWarningThreshold; const status = slow ? ' (slow)' : ''; if (exception != null) { @@ -282,7 +283,7 @@ export class Git { } else { Logger.log(`[SGIT ] ${gitCommand} ${GlyphChars.Dot} ${duration} ms${status}`); } - Logger.logGitCommand( + this.logGitCommand( `${gitCommand}${exception != null ? ` ${GlyphChars.Dot} FAILED` : ''}`, duration, exception, @@ -1896,6 +1897,33 @@ export class Git { return undefined; } } + + private _gitOutput: OutputChannel | undefined; + + private logGitCommand(command: string, duration: number, ex?: Error): void { + if (Logger.enabled(LogLevel.Debug) && !Logger.isDebugging) return; + + const slow = duration > slowCallWarningThreshold; + + if (Logger.isDebugging) { + if (ex != null) { + console.error(Logger.timestamp, '[GitLens (Git)]', command ?? emptyStr, ex); + } else if (slow) { + console.warn(Logger.timestamp, '[GitLens (Git)]', command ?? emptyStr); + } else { + console.log(Logger.timestamp, '[GitLens (Git)]', command ?? emptyStr); + } + } + + if (this._gitOutput == null) { + this._gitOutput = window.createOutputChannel('GitLens (Git)'); + } + this._gitOutput.appendLine( + `${Logger.timestamp} [${slow ? '*' : ' '}${duration.toString().padStart(6)}ms] ${command}${ + ex != null ? `\n\n${ex.toString()}` : emptyStr + }`, + ); + } } export function getShaInLogRegex(sha: string) { diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index b462f1e..b14e4f0 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -116,8 +116,9 @@ import { getRemoteProviderMatcher, loadRemoteProviders } from '../../../git/remo import type { RichRemoteProvider } from '../../../git/remotes/richRemoteProvider'; import type { GitSearch, GitSearchResultData, GitSearchResults, SearchQuery } from '../../../git/search'; import { getGitArgsFromSearchQuery, getSearchQueryComparisonKey } from '../../../git/search'; -import type { LogScope } from '../../../logger'; import { Logger } from '../../../logger'; +import type { LogScope } from '../../../logScope'; +import { getLogScope } from '../../../logScope'; import { showGenericErrorMessage, showGitDisabledErrorMessage, @@ -135,7 +136,7 @@ import type { import { countStringLength, filterMap } from '../../../system/array'; import { TimedCancellationSource } from '../../../system/cancellation'; import { gate } from '../../../system/decorators/gate'; -import { debug, getLogScope, log } from '../../../system/decorators/log'; +import { debug, log } from '../../../system/decorators/log'; import { filterMap as filterMapIterable, find, first, join, last, map, some } from '../../../system/iterable'; import { commonBaseIndex, diff --git a/src/env/node/git/locator.ts b/src/env/node/git/locator.ts index 982c9be..fa93bb5 100644 --- a/src/env/node/git/locator.ts +++ b/src/env/node/git/locator.ts @@ -1,7 +1,6 @@ import { join as joinPaths } from 'path'; import * as process from 'process'; -import { GlyphChars } from '../../../constants'; -import { LogLevel } from '../../../logger'; +import { GlyphChars, LogLevel } from '../../../constants'; import { any } from '../../../system/promise'; import { Stopwatch } from '../../../system/stopwatch'; import { findExecutable, run } from './shell'; diff --git a/src/env/node/git/vslsGitProvider.ts b/src/env/node/git/vslsGitProvider.ts index 55776fa..f30d882 100644 --- a/src/env/node/git/vslsGitProvider.ts +++ b/src/env/node/git/vslsGitProvider.ts @@ -6,7 +6,7 @@ import type { GitProviderDescriptor } from '../../../git/gitProvider'; import { GitProviderId } from '../../../git/gitProvider'; import type { Repository } from '../../../git/models/repository'; import { Logger } from '../../../logger'; -import { getLogScope } from '../../../system/decorators/log'; +import { getLogScope } from '../../../logScope'; import { addVslsPrefixIfNeeded } from '../../../system/path'; import { Git } from './git'; import { LocalGitProvider } from './localGitProvider'; diff --git a/src/extension.ts b/src/extension.ts index d052ddb..576c2b2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,19 +1,19 @@ import type { ExtensionContext } from 'vscode'; -import { version as codeVersion, env, extensions, window, workspace } from 'vscode'; +import { version as codeVersion, env, ExtensionMode, extensions, Uri, window, workspace } from 'vscode'; import { hrtime } from '@env/hrtime'; import { isWeb } from '@env/platform'; import { Api } from './api/api'; import type { CreatePullRequestActionContext, GitLensApi, OpenPullRequestActionContext } from './api/gitlens'; import type { CreatePullRequestOnRemoteCommandArgs, OpenPullRequestOnRemoteCommandArgs } from './commands'; -import { configuration, Configuration, OutputLevel } from './configuration'; -import { Commands, ContextKeys, CoreCommands } from './constants'; +import { configuration, Configuration, fromOutputLevel, OutputLevel } from './configuration'; +import { Commands, ContextKeys, CoreCommands, LogLevel } from './constants'; import { Container } from './container'; import { setContext } from './context'; import { isGitUri } from './git/gitUri'; import { getBranchNameWithoutRemote, isBranch } from './git/models/branch'; import { isCommit } from './git/models/commit'; import { isTag } from './git/models/tag'; -import { Logger, LogLevel } from './logger'; +import { Logger } from './logger'; import { showDebugLoggingWarningMessage, showInsidersErrorMessage, @@ -36,17 +36,28 @@ export async function activate(context: ExtensionContext): Promise 2020.0.0'); const outputLevel = configuration.get('outputLevel'); - Logger.configure(context, configuration.get('outputLevel'), o => { - if (isGitUri(o)) { - return `GitUri(${o.toString(true)}${o.repoPath ? ` repoPath=${o.repoPath}` : ''}${ - o.sha ? ` sha=${o.sha}` : '' - })`; - } + Logger.configure( + { + name: 'GitLens', + createChannel: function (name: string) { + return window.createOutputChannel(name); + }, + toLoggable: function (o: any) { + if (isGitUri(o)) { + return `GitUri(${o.toString(true)}${o.repoPath ? ` repoPath=${o.repoPath}` : ''}${ + o.sha ? ` sha=${o.sha}` : '' + })`; + } + if (o instanceof Uri) return `Uri(${o.toString(true)})`; - if (isBranch(o) || isCommit(o) || isTag(o) || isViewNode(o)) return o.toString(); + if (isBranch(o) || isCommit(o) || isTag(o) || isViewNode(o)) return o.toString(); - return undefined; - }); + return undefined; + }, + }, + fromOutputLevel(configuration.get('outputLevel')), + context.extensionMode === ExtensionMode.Development, + ); const sw = new Stopwatch( `GitLens${prerelease ? (insiders ? ' (Insiders)' : ' (pre-release)') : ''} v${gitlensVersion}`, diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index 72c374b..74aef8d 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -18,6 +18,7 @@ import { setContext } from '../context'; import { AccessDeniedError, ProviderNotFoundError } from '../errors'; import type { FeatureAccess, Features, PlusFeatures, RepoFeatureAccess } from '../features'; import { Logger } from '../logger'; +import { getLogScope } from '../logScope'; import type { SubscriptionChangeEvent } from '../plus/subscription/subscriptionService'; import type { RepoComparisonKey } from '../repositories'; import { asRepoComparisonKey, Repositories } from '../repositories'; @@ -25,7 +26,7 @@ import type { Subscription } from '../subscription'; import { isSubscriptionPaidPlan, SubscriptionPlanId } from '../subscription'; import { groupByFilterMap, groupByMap, joinUnique } from '../system/array'; import { gate } from '../system/decorators/gate'; -import { debug, getLogScope, log } from '../system/decorators/log'; +import { debug, log } from '../system/decorators/log'; import { count, filter, first, flatMap, join, map, some } from '../system/iterable'; import { getBestPath, getScheme, isAbsolute, maybeUri, normalizePath } from '../system/path'; import { cancellable, fastestSettled, getSettledValue, isPromise, PromiseCancelledError } from '../system/promise'; diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index b99e394..25d8b7f 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -8,13 +8,14 @@ import { CoreGitCommands, CoreGitConfiguration, Schemes } from '../../constants' import type { Container } from '../../container'; import type { FeatureAccess, Features, PlusFeatures } from '../../features'; import { Logger } from '../../logger'; +import { getLogScope } from '../../logScope'; import { showCreatePullRequestPrompt, showGenericErrorMessage } from '../../messages'; import { asRepoComparisonKey } from '../../repositories'; import { filterMap, groupByMap } from '../../system/array'; import { executeActionCommand, executeCoreGitCommand } from '../../system/command'; import { formatDate, fromNow } from '../../system/date'; import { gate } from '../../system/decorators/gate'; -import { debug, getLogScope, log, logName } from '../../system/decorators/log'; +import { debug, log, logName } from '../../system/decorators/log'; import { debounce } from '../../system/function'; import { filter, join, some } from '../../system/iterable'; import { updateRecordValue } from '../../system/object'; diff --git a/src/git/remotes/richRemoteProvider.ts b/src/git/remotes/richRemoteProvider.ts index cf7e710..44662d2 100644 --- a/src/git/remotes/richRemoteProvider.ts +++ b/src/git/remotes/richRemoteProvider.ts @@ -6,11 +6,12 @@ import { configuration } from '../../configuration'; import type { Container } from '../../container'; import { AuthenticationError, ProviderRequestClientError } from '../../errors'; import { Logger } from '../../logger'; +import { getLogScope } from '../../logScope'; import { showIntegrationDisconnectedTooManyFailedRequestsWarningMessage } from '../../messages'; import type { IntegrationAuthenticationSessionDescriptor } from '../../plus/integrationAuthentication'; import { isSubscriptionPaidPlan, isSubscriptionPreviewTrialExpired } from '../../subscription'; import { gate } from '../../system/decorators/gate'; -import { debug, getLogScope, log } from '../../system/decorators/log'; +import { debug, log } from '../../system/decorators/log'; import { isPromise } from '../../system/promise'; import type { Account } from '../models/author'; import type { DefaultBranch } from '../models/defaultBranch'; diff --git a/src/hovers/hovers.ts b/src/hovers/hovers.ts index 6384f24..347ae4c 100644 --- a/src/hovers/hovers.ts +++ b/src/hovers/hovers.ts @@ -3,7 +3,7 @@ import { MarkdownString } from 'vscode'; import { hrtime } from '@env/hrtime'; import { DiffWithCommand, ShowQuickCommitCommand } from '../commands'; import { configuration } from '../configuration'; -import { GlyphChars } from '../constants'; +import { GlyphChars, LogLevel } from '../constants'; import { Container } from '../container'; import { CommitFormatter } from '../git/formatters/commitFormatter'; import { GitUri } from '../git/gitUri'; @@ -12,8 +12,8 @@ import type { GitDiffHunk, GitDiffHunkLine } from '../git/models/diff'; import type { PullRequest } from '../git/models/pullRequest'; import { GitRevision } from '../git/models/reference'; import type { GitRemote } from '../git/models/remote'; -import { Logger, LogLevel } from '../logger'; -import { getNewLogScope } from '../system/decorators/log'; +import { Logger } from '../logger'; +import { getNewLogScope } from '../logScope'; import { count } from '../system/iterable'; import { getSettledValue, PromiseCancelledError } from '../system/promise'; import { getDurationMilliseconds } from '../system/string'; diff --git a/src/keyboard.ts b/src/keyboard.ts index 40de8c7..33ea52d 100644 --- a/src/keyboard.ts +++ b/src/keyboard.ts @@ -2,8 +2,9 @@ import { Disposable } from 'vscode'; import { ContextKeys } from './constants'; import { setContext } from './context'; import { Logger } from './logger'; +import { getLogScope } from './logScope'; import { registerCommand } from './system/command'; -import { getLogScope, log } from './system/decorators/log'; +import { log } from './system/decorators/log'; export declare interface KeyCommand { onDidPressKey?(key: Keys): void | Promise; diff --git a/src/logScope.ts b/src/logScope.ts new file mode 100644 index 0000000..345ee94 --- /dev/null +++ b/src/logScope.ts @@ -0,0 +1,41 @@ +const maxSmallIntegerV8 = 2 ** 30; // Max number that can be stored in V8's smis (small integers) + +const scopes = new Map(); +let scopeCounter = 0; + +export interface LogScope { + readonly scopeId?: number; + readonly prefix: string; + exitDetails?: string; +} + +export function clearLogScope(scopeId: number) { + scopes.delete(scopeId); +} + +export function getLogScope(): LogScope | undefined { + return scopes.get(scopeCounter); +} + +export function getNewLogScope(prefix: string): LogScope { + const scopeId = getNextLogScopeId(); + return { + scopeId: scopeId, + prefix: `[${String(scopeId).padStart(5)}] ${prefix}`, + }; +} + +export function getLogScopeId(): number { + return scopeCounter; +} + +export function getNextLogScopeId(): number { + if (scopeCounter === maxSmallIntegerV8) { + scopeCounter = 0; + } + return ++scopeCounter; +} + +export function setLogScope(scopeId: number, scope: LogScope) { + scopes.set(scopeId, scope); +} diff --git a/src/logger.ts b/src/logger.ts index 61f7fce..3e491bb 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,27 +1,7 @@ -import type { ExtensionContext, OutputChannel } from 'vscode'; -import { ExtensionMode, Uri, window } from 'vscode'; -import { OutputLevel } from './configuration'; +import { LogLevel } from './constants'; +import type { LogScope } from './logScope'; const emptyStr = ''; -const outputChannelName = 'GitLens'; -const consolePrefix = '[GitLens]'; - -const gitOutputChannelName = 'GitLens (Git)'; -const gitConsolePrefix = '[GitLens (Git)]'; - -export const enum LogLevel { - Off = 'off', - Error = 'error', - Warn = 'warn', - Info = 'info', - Debug = 'debug', -} - -export interface LogScope { - readonly scopeId?: number; - readonly prefix: string; - exitDetails?: string; -} const enum OrderedLevel { Off = 0, @@ -31,48 +11,63 @@ const enum OrderedLevel { Debug = 4, } -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class Logger { - static readonly slowCallWarningThreshold = 500; +export interface LogChannelProvider { + readonly name: string; + createChannel(name: string): LogChannel; + toLoggable?(o: unknown): string | undefined; +} - private static output: OutputChannel | undefined; - private static customLoggableFn: ((o: object) => string | undefined) | undefined; +export interface LogChannel { + readonly name: string; + appendLine(value: string): void; + dispose(): void; + show(preserveFocus?: boolean): void; +} - static configure(context: ExtensionContext, outputLevel: OutputLevel, loggableFn?: (o: any) => string | undefined) { - this._isDebugging = context.extensionMode === ExtensionMode.Development; - this.logLevel = outputLevel; - this.customLoggableFn = loggableFn; +export const Logger = new (class Logger { + private output: LogChannel | undefined; + private provider: LogChannelProvider | undefined; + + configure(provider: LogChannelProvider, logLevel: LogLevel, debugging: boolean = false) { + this.provider = provider; + + this._isDebugging = debugging; + this.logLevel = logLevel; } - static enabled(level: LogLevel): boolean { + enabled(level: LogLevel): boolean { return this.level >= toOrderedLevel(level); } - private static _isDebugging: boolean; - static get isDebugging() { + private _isDebugging = false; + get isDebugging() { return this._isDebugging; } - private static level: OrderedLevel = OrderedLevel.Off; - private static _logLevel: LogLevel = LogLevel.Off; - static get logLevel(): LogLevel { + private level: OrderedLevel = OrderedLevel.Off; + private _logLevel: LogLevel = LogLevel.Off; + get logLevel(): LogLevel { return this._logLevel; } - static set logLevel(value: LogLevel | OutputLevel) { - this._logLevel = fromOutputLevel(value); + set logLevel(value: LogLevel) { + this._logLevel = value; this.level = toOrderedLevel(this._logLevel); if (value === LogLevel.Off) { this.output?.dispose(); this.output = undefined; } else { - this.output = this.output ?? window.createOutputChannel(outputChannelName); + this.output = this.output ?? this.provider!.createChannel(this.provider!.name); } } - static debug(message: string, ...params: any[]): void; - static debug(scope: LogScope | undefined, message: string, ...params: any[]): void; - static debug(scopeOrMessage: LogScope | string | undefined, ...params: any[]): void { + get timestamp(): string { + return `[${new Date().toISOString().replace(/T/, ' ').slice(0, -1)}]`; + } + + debug(message: string, ...params: any[]): void; + debug(scope: LogScope | undefined, message: string, ...params: any[]): void; + debug(scopeOrMessage: LogScope | string | undefined, ...params: any[]): void { if (this.level < OrderedLevel.Debug && !this.isDebugging) return; let message; @@ -87,16 +82,16 @@ export class Logger { } if (this.isDebugging) { - console.log(this.timestamp, consolePrefix, message ?? emptyStr, ...params); + console.log(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params); } if (this.output == null || this.level < OrderedLevel.Debug) return; this.output.appendLine(`${this.timestamp} ${message ?? emptyStr}${this.toLoggableParams(true, params)}`); } - static error(ex: Error | unknown, message?: string, ...params: any[]): void; - static error(ex: Error | unknown, scope?: LogScope, message?: string, ...params: any[]): void; - static error(ex: Error | unknown, scopeOrMessage: LogScope | string | undefined, ...params: any[]): void { + error(ex: Error | unknown, message?: string, ...params: any[]): void; + error(ex: Error | unknown, scope?: LogScope, message?: string, ...params: any[]): void; + error(ex: Error | unknown, scopeOrMessage: LogScope | string | undefined, ...params: any[]): void { if (this.level < OrderedLevel.Error && !this.isDebugging) return; let message; @@ -117,7 +112,7 @@ export class Logger { } if (this.isDebugging) { - console.error(this.timestamp, consolePrefix, message ?? emptyStr, ...params, ex); + console.error(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params, ex); } if (this.output == null || this.level < OrderedLevel.Error) return; @@ -126,9 +121,9 @@ export class Logger { ); } - static log(message: string, ...params: any[]): void; - static log(scope: LogScope | undefined, message: string, ...params: any[]): void; - static log(scopeOrMessage: LogScope | string | undefined, ...params: any[]): void { + log(message: string, ...params: any[]): void; + log(scope: LogScope | undefined, message: string, ...params: any[]): void; + log(scopeOrMessage: LogScope | string | undefined, ...params: any[]): void { if (this.level < OrderedLevel.Info && !this.isDebugging) return; let message; @@ -143,16 +138,16 @@ export class Logger { } if (this.isDebugging) { - console.log(this.timestamp, consolePrefix, message ?? emptyStr, ...params); + console.log(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params); } if (this.output == null || this.level < OrderedLevel.Info) return; this.output.appendLine(`${this.timestamp} ${message ?? emptyStr}${this.toLoggableParams(false, params)}`); } - static warn(message: string, ...params: any[]): void; - static warn(scope: LogScope | undefined, message: string, ...params: any[]): void; - static warn(scopeOrMessage: LogScope | string | undefined, ...params: any[]): void { + warn(message: string, ...params: any[]): void; + warn(scope: LogScope | undefined, message: string, ...params: any[]): void; + warn(scopeOrMessage: LogScope | string | undefined, ...params: any[]): void { if (this.level < OrderedLevel.Warn && !this.isDebugging) return; let message; @@ -167,37 +162,31 @@ export class Logger { } if (this.isDebugging) { - console.warn(this.timestamp, consolePrefix, message ?? emptyStr, ...params); + console.warn(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params); } if (this.output == null || this.level < OrderedLevel.Warn) return; this.output.appendLine(`${this.timestamp} ${message ?? emptyStr}${this.toLoggableParams(false, params)}`); } - static showOutputChannel(): void { - this.output?.show(); + showOutputChannel(preserveFocus?: boolean): void { + this.output?.show(preserveFocus); } - static toLoggable(p: any, sanitize?: ((key: string, value: any) => any) | undefined) { - if (typeof p !== 'object') return String(p); - if (this.customLoggableFn != null) { - const loggable = this.customLoggableFn(p); - if (loggable != null) return loggable; - } - if (p instanceof Uri) return `Uri(${p.toString(true)})`; + toLoggable(o: any, sanitize?: ((key: string, value: any) => any) | undefined) { + if (typeof o !== 'object') return String(o); + + const loggable = this.provider!.toLoggable?.(o); + if (loggable != null) return loggable; try { - return JSON.stringify(p, sanitize); + return JSON.stringify(o, sanitize); } catch { return ''; } } - private static get timestamp(): string { - return `[${new Date().toISOString().replace(/T/, ' ').slice(0, -1)}]`; - } - - private static toLoggableParams(debugOnly: boolean, params: any[]) { + private toLoggableParams(debugOnly: boolean, params: any[]) { if (params.length === 0 || (debugOnly && this.level < OrderedLevel.Debug && !this.isDebugging)) { return emptyStr; } @@ -205,49 +194,7 @@ export class Logger { const loggableParams = params.map(p => this.toLoggable(p)).join(', '); return loggableParams.length !== 0 ? ` \u2014 ${loggableParams}` : emptyStr; } - - static gitOutput: OutputChannel | undefined; - - static logGitCommand(command: string, duration: number, ex?: Error): void { - if (this.level < OrderedLevel.Debug && !this.isDebugging) return; - - const slow = duration > Logger.slowCallWarningThreshold; - - if (this.isDebugging) { - if (ex != null) { - console.error(this.timestamp, gitConsolePrefix, command ?? emptyStr, ex); - } else if (slow) { - console.warn(this.timestamp, gitConsolePrefix, command ?? emptyStr); - } else { - console.log(this.timestamp, gitConsolePrefix, command ?? emptyStr); - } - } - - if (this.gitOutput == null) { - this.gitOutput = window.createOutputChannel(gitOutputChannelName); - } - this.gitOutput.appendLine( - `${this.timestamp} [${slow ? '*' : ' '}${duration.toString().padStart(6)}ms] ${command}${ - ex != null ? `\n\n${ex.toString()}` : emptyStr - }`, - ); - } -} - -function fromOutputLevel(level: LogLevel | OutputLevel): LogLevel { - switch (level) { - case OutputLevel.Silent: - return LogLevel.Off; - case OutputLevel.Errors: - return LogLevel.Error; - case OutputLevel.Verbose: - return LogLevel.Info; - case OutputLevel.Debug: - return LogLevel.Debug; - default: - return level; - } -} +})(); function toOrderedLevel(logLevel: LogLevel): OrderedLevel { switch (logLevel) { @@ -280,3 +227,28 @@ export function getLoggableName(instance: Function | object) { const index = name.indexOf('_'); return index === -1 ? name : name.substr(index + 1); } + +export interface LogProvider { + enabled(logLevel: LogLevel): boolean; + log(logLevel: LogLevel, scope: LogScope | undefined, message: string, ...params: any[]): void; +} + +export const defaultLogProvider: LogProvider = { + enabled: (logLevel: LogLevel) => Logger.enabled(logLevel), + log: (logLevel: LogLevel, scope: LogScope | undefined, message: string, ...params: any[]) => { + switch (logLevel) { + case LogLevel.Error: + Logger.error('', scope, message, ...params); + break; + case LogLevel.Warn: + Logger.warn(scope, message, ...params); + break; + case LogLevel.Info: + Logger.log(scope, message, ...params); + break; + default: + Logger.debug(scope, message, ...params); + break; + } + }, +}; diff --git a/src/messages.ts b/src/messages.ts index 42539d6..9dbdac4 100644 --- a/src/messages.ts +++ b/src/messages.ts @@ -1,9 +1,9 @@ import type { MessageItem } from 'vscode'; import { ConfigurationTarget, env, Uri, window } from 'vscode'; import { configuration, SuppressedMessages } from './configuration'; -import { Commands } from './constants'; +import { Commands, LogLevel } from './constants'; import type { GitCommit } from './git/models/commit'; -import { Logger, LogLevel } from './logger'; +import { Logger } from './logger'; import { executeCommand } from './system/command'; export function showCommitHasNoPreviousCommitWarningMessage(commit?: GitCommit): Promise { diff --git a/src/plus/github/github.ts b/src/plus/github/github.ts index dfd5b71..6d76859 100644 --- a/src/plus/github/github.ts +++ b/src/plus/github/github.ts @@ -8,6 +8,7 @@ import { Disposable, EventEmitter, Uri, window } from 'vscode'; import { fetch, getProxyAgent, wrapForForcedInsecureSSL } from '@env/fetch'; import { isWeb } from '@env/platform'; import { configuration } from '../../configuration'; +import { LogLevel } from '../../constants'; import type { Container } from '../../container'; import { AuthenticationError, @@ -26,13 +27,14 @@ import { GitRevision } from '../../git/models/reference'; import type { GitUser } from '../../git/models/user'; import { getGitHubNoReplyAddressParts } from '../../git/remotes/github'; import type { RichRemoteProvider } from '../../git/remotes/richRemoteProvider'; -import type { LogScope } from '../../logger'; -import { Logger, LogLevel } from '../../logger'; +import { Logger } from '../../logger'; +import type { LogScope } from '../../logScope'; +import { getLogScope } from '../../logScope'; import { showIntegrationRequestFailed500WarningMessage, showIntegrationRequestTimedOutWarningMessage, } from '../../messages'; -import { debug, getLogScope } from '../../system/decorators/log'; +import { debug } from '../../system/decorators/log'; import { Stopwatch } from '../../system/stopwatch'; import { base64 } from '../../system/string'; import type { Version } from '../../system/version'; diff --git a/src/plus/github/githubGitProvider.ts b/src/plus/github/githubGitProvider.ts index 0a9a17f..96e8d88 100644 --- a/src/plus/github/githubGitProvider.ts +++ b/src/plus/github/githubGitProvider.ts @@ -78,10 +78,11 @@ import { getRemoteProviderMatcher, loadRemoteProviders } from '../../git/remotes import type { RichRemoteProvider } from '../../git/remotes/richRemoteProvider'; import type { GitSearch, GitSearchResultData, GitSearchResults, SearchQuery } from '../../git/search'; import { getSearchQueryComparisonKey, parseSearchQuery } from '../../git/search'; -import type { LogScope } from '../../logger'; import { Logger } from '../../logger'; +import type { LogScope } from '../../logScope'; +import { getLogScope } from '../../logScope'; import { gate } from '../../system/decorators/gate'; -import { debug, getLogScope, log } from '../../system/decorators/log'; +import { debug, log } from '../../system/decorators/log'; import { filterMap, first, last, some } from '../../system/iterable'; import { isAbsolute, isFolderGlob, maybeUri, normalizePath, relative } from '../../system/path'; import { fastestSettled, getSettledValue } from '../../system/promise'; diff --git a/src/plus/gitlab/gitlab.ts b/src/plus/gitlab/gitlab.ts index edc87f9..c941932 100644 --- a/src/plus/gitlab/gitlab.ts +++ b/src/plus/gitlab/gitlab.ts @@ -4,6 +4,7 @@ import type { RequestInit, Response } from '@env/fetch'; import { fetch, getProxyAgent, wrapForForcedInsecureSSL } from '@env/fetch'; import { isWeb } from '@env/platform'; import { configuration } from '../../configuration'; +import { LogLevel } from '../../constants'; import type { Container } from '../../container'; import { AuthenticationError, @@ -19,13 +20,14 @@ import type { IssueOrPullRequest } from '../../git/models/issue'; import { IssueOrPullRequestType } from '../../git/models/issue'; import { PullRequest } from '../../git/models/pullRequest'; import type { RichRemoteProvider } from '../../git/remotes/richRemoteProvider'; -import type { LogScope } from '../../logger'; -import { Logger, LogLevel } from '../../logger'; +import { Logger } from '../../logger'; +import type { LogScope } from '../../logScope'; +import { getLogScope } from '../../logScope'; import { showIntegrationRequestFailed500WarningMessage, showIntegrationRequestTimedOutWarningMessage, } from '../../messages'; -import { debug, getLogScope } from '../../system/decorators/log'; +import { debug } from '../../system/decorators/log'; import { Stopwatch } from '../../system/stopwatch'; import { equalsIgnoreCase } from '../../system/string'; import type { GitLabCommit, GitLabIssue, GitLabUser } from './models'; diff --git a/src/plus/subscription/authenticationProvider.ts b/src/plus/subscription/authenticationProvider.ts index 397e326..460ce85 100644 --- a/src/plus/subscription/authenticationProvider.ts +++ b/src/plus/subscription/authenticationProvider.ts @@ -7,7 +7,8 @@ import { authentication, Disposable, EventEmitter, extensions, window } from 'vs import { uuid } from '@env/crypto'; import type { Container } from '../../container'; import { Logger } from '../../logger'; -import { debug, getLogScope } from '../../system/decorators/log'; +import { getLogScope } from '../../logScope'; +import { debug } from '../../system/decorators/log'; import type { ServerConnection } from './serverConnection'; interface StoredSession { diff --git a/src/plus/subscription/serverConnection.ts b/src/plus/subscription/serverConnection.ts index 29725b9..3d35b2c 100644 --- a/src/plus/subscription/serverConnection.ts +++ b/src/plus/subscription/serverConnection.ts @@ -5,7 +5,8 @@ import type { Response } from '@env/fetch'; import { fetch, getProxyAgent } from '@env/fetch'; import type { Container } from '../../container'; import { Logger } from '../../logger'; -import { debug, getLogScope } from '../../system/decorators/log'; +import { getLogScope } from '../../logScope'; +import { debug } from '../../system/decorators/log'; import { memoize } from '../../system/decorators/memoize'; import type { DeferredEvent, DeferredEventExecutor } from '../../system/event'; import { promisifyDeferred } from '../../system/event'; diff --git a/src/plus/subscription/subscriptionService.ts b/src/plus/subscription/subscriptionService.ts index 1915f13..39f8021 100644 --- a/src/plus/subscription/subscriptionService.ts +++ b/src/plus/subscription/subscriptionService.ts @@ -29,6 +29,7 @@ import { setContext } from '../../context'; import { AccountValidationError } from '../../errors'; import type { RepositoriesChangeEvent } from '../../git/gitProviderService'; import { Logger } from '../../logger'; +import { getLogScope } from '../../logScope'; import type { Subscription } from '../../subscription'; import { computeSubscriptionState, @@ -46,7 +47,7 @@ import { import { executeCommand, registerCommand } from '../../system/command'; import { createFromDateDelta } from '../../system/date'; import { gate } from '../../system/decorators/gate'; -import { debug, getLogScope, log } from '../../system/decorators/log'; +import { debug, log } from '../../system/decorators/log'; import { memoize } from '../../system/decorators/memoize'; import type { Deferrable } from '../../system/function'; import { debounce, once } from '../../system/function'; diff --git a/src/statusbar/statusBarController.ts b/src/statusbar/statusBarController.ts index a184e4f..c1c9624 100644 --- a/src/statusbar/statusBarController.ts +++ b/src/statusbar/statusBarController.ts @@ -8,10 +8,11 @@ import { CommitFormatter } from '../git/formatters/commitFormatter'; import type { GitCommit } from '../git/models/commit'; import type { PullRequest } from '../git/models/pullRequest'; import { detailsMessage } from '../hovers/hovers'; -import type { LogScope } from '../logger'; import { Logger } from '../logger'; +import type { LogScope } from '../logScope'; +import { getLogScope } from '../logScope'; import { asCommand } from '../system/command'; -import { debug, getLogScope } from '../system/decorators/log'; +import { debug } from '../system/decorators/log'; import { once } from '../system/event'; import { PromiseCancelledError } from '../system/promise'; import { isTextEditor } from '../system/utils'; diff --git a/src/system/decorators/log.ts b/src/system/decorators/log.ts index b0d66b7..2625755 100644 --- a/src/system/decorators/log.ts +++ b/src/system/decorators/log.ts @@ -1,47 +1,14 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ import { hrtime } from '@env/hrtime'; -import type { LogScope } from '../../logger'; -import { getLoggableName, Logger, LogLevel } from '../../logger'; +import { LogLevel, slowCallWarningThreshold } from '../../constants'; +import { getLoggableName, Logger } from '../../logger'; +import type { LogScope } from '../../logScope'; +import { clearLogScope, getNextLogScopeId, setLogScope } from '../../logScope'; import { getParameters } from '../function'; import { isPromise } from '../promise'; import { getDurationMilliseconds } from '../string'; const emptyStr = ''; -const maxSmallIntegerV8 = 2 ** 30; // Max number that can be stored in V8's smis (small integers) - -const scopes = new Map(); -let scopeCounter = 0; - -export function getLogScope(): LogScope | undefined { - return scopes.get(scopeCounter); -} - -export function getNewLogScope(prefix: string): LogScope { - const scopeId = getNextLogScopeId(); - return { - scopeId: scopeId, - prefix: `[${String(scopeId).padStart(5)}] ${prefix}`, - }; -} - -export function getLogScopeId(): number { - return scopeCounter; -} - -export function getNextLogScopeId(): number { - if (scopeCounter === maxSmallIntegerV8) { - scopeCounter = 0; - } - return ++scopeCounter; -} - -function clearLogScope(scopeId: number) { - scopes.delete(scopeId); -} - -function setLogScope(scopeId: number, scope: LogScope) { - scopes.set(scopeId, scope); -} export interface LogContext { id: number; @@ -277,7 +244,7 @@ export function log any>(options?: LogOptions, deb let timing; if (start != null) { duration = getDurationMilliseconds(start); - if (duration > Logger.slowCallWarningThreshold) { + if (duration > slowCallWarningThreshold) { exitLogFn = warnFn; timing = ` \u2022 ${duration} ms (slow)`; } else { diff --git a/src/system/stopwatch.ts b/src/system/stopwatch.ts index 8e0cd06..fadc4d3 100644 --- a/src/system/stopwatch.ts +++ b/src/system/stopwatch.ts @@ -1,19 +1,22 @@ import { hrtime } from '@env/hrtime'; -import { GlyphChars } from '../constants'; -import type { LogScope } from '../logger'; -import { Logger, LogLevel } from '../logger'; -import { getNextLogScopeId } from './decorators/log'; +import { GlyphChars, LogLevel } from '../constants'; +import type { LogProvider } from '../logger'; +import { defaultLogProvider } from '../logger'; +import type { LogScope } from '../logScope'; +import { getNextLogScopeId } from '../logScope'; type StopwatchLogOptions = { message?: string; suffix?: string }; type StopwatchOptions = { log?: boolean | StopwatchLogOptions; logLevel?: StopwatchLogLevel; + provider?: LogProvider; }; type StopwatchLogLevel = Exclude; export class Stopwatch { private readonly instance = `[${String(getNextLogScopeId()).padStart(5)}] `; private readonly logLevel: StopwatchLogLevel; + private readonly logProvider: LogProvider; private _time: [number, number]; get startTime() { @@ -36,20 +39,21 @@ export class Stopwatch { } this.logLevel = options?.logLevel ?? LogLevel.Info; + this.logProvider = options?.provider ?? defaultLogProvider; this._time = hrtime(); if (logOptions != null) { - if (!Logger.enabled(this.logLevel)) return; + if (!this.logProvider.enabled(this.logLevel)) return; if (params.length) { - log( + this.logProvider.log( this.logLevel, logScope, `${this.instance}${scope}${logOptions.message ?? ''}${logOptions.suffix ?? ''}`, ...params, ); } else { - log( + this.logProvider.log( this.logLevel, logScope, `${this.instance}${scope}${logOptions.message ?? ''}${logOptions.suffix ?? ''}`, @@ -81,7 +85,7 @@ export class Stopwatch { options: StopwatchLogOptions | undefined, logTotalElapsed: boolean, ): void { - if (!Logger.enabled(this.logLevel)) return; + if (!this.logProvider.enabled(this.logLevel)) return; let logScope; if (typeof scope !== 'string') { @@ -90,7 +94,11 @@ export class Stopwatch { } if (!logTotalElapsed) { - log(this.logLevel, logScope, `${this.instance}${scope}${options?.message ?? ''}${options?.suffix ?? ''}`); + this.logProvider.log( + this.logLevel, + logScope, + `${this.instance}${scope}${options?.message ?? ''}${options?.suffix ?? ''}`, + ); return; } @@ -99,7 +107,7 @@ export class Stopwatch { const ms = secs * 1000 + Math.floor(nanosecs / 1000000); const prefix = `${this.instance}${scope}${options?.message ?? ''}`; - log( + this.logProvider.log( ms > 250 ? LogLevel.Warn : this.logLevel, logScope, `${prefix ? `${prefix} ${GlyphChars.Dot} ` : ''}${ms} ms${options?.suffix ?? ''}`, @@ -122,20 +130,3 @@ export class Stopwatch { Stopwatch.watches.delete(key); } } - -function log(logLevel: StopwatchLogLevel, scope: LogScope | undefined, message: string, ...params: any[]) { - switch (logLevel) { - case LogLevel.Error: - Logger.error('', scope, message, ...params); - break; - case LogLevel.Warn: - Logger.warn(scope, message, ...params); - break; - case LogLevel.Info: - Logger.log(scope, message, ...params); - break; - default: - Logger.debug(scope, message, ...params); - break; - } -} diff --git a/src/trackers/gitLineTracker.ts b/src/trackers/gitLineTracker.ts index 02baaef..e039dcb 100644 --- a/src/trackers/gitLineTracker.ts +++ b/src/trackers/gitLineTracker.ts @@ -4,7 +4,8 @@ import { configuration } from '../configuration'; import { GlyphChars } from '../constants'; import type { Container } from '../container'; import type { GitCommit } from '../git/models/commit'; -import { debug, getLogScope } from '../system/decorators/log'; +import { getLogScope } from '../logScope'; +import { debug } from '../system/decorators/log'; import type { DocumentBlameStateChangeEvent, DocumentContentChangeEvent, diff --git a/src/trackers/lineTracker.ts b/src/trackers/lineTracker.ts index 53e24f6..c0fdb9f 100644 --- a/src/trackers/lineTracker.ts +++ b/src/trackers/lineTracker.ts @@ -1,7 +1,8 @@ import type { Event, Selection, TextEditor, TextEditorSelectionChangeEvent } from 'vscode'; import { Disposable, EventEmitter, window } from 'vscode'; import { Logger } from '../logger'; -import { debug, getLogScope } from '../system/decorators/log'; +import { getLogScope } from '../logScope'; +import { debug } from '../system/decorators/log'; import type { Deferrable } from '../system/function'; import { debounce } from '../system/function'; import { isTextEditor } from '../system/utils'; diff --git a/src/views/nodes/fileHistoryTrackerNode.ts b/src/views/nodes/fileHistoryTrackerNode.ts index 2a16b02..98e5990 100644 --- a/src/views/nodes/fileHistoryTrackerNode.ts +++ b/src/views/nodes/fileHistoryTrackerNode.ts @@ -7,9 +7,10 @@ import type { GitCommitish } from '../../git/gitUri'; import { GitUri, unknownGitUri } from '../../git/gitUri'; import { GitReference, GitRevision } from '../../git/models/reference'; import { Logger } from '../../logger'; +import { getLogScope } from '../../logScope'; import { ReferencePicker } from '../../quickpicks/referencePicker'; import { gate } from '../../system/decorators/gate'; -import { debug, getLogScope, log } from '../../system/decorators/log'; +import { debug, log } from '../../system/decorators/log'; import type { Deferrable } from '../../system/function'; import { debounce } from '../../system/function'; import { isVirtualUri } from '../../system/utils'; diff --git a/src/views/nodes/lineHistoryTrackerNode.ts b/src/views/nodes/lineHistoryTrackerNode.ts index b968e98..7c6c18d 100644 --- a/src/views/nodes/lineHistoryTrackerNode.ts +++ b/src/views/nodes/lineHistoryTrackerNode.ts @@ -7,9 +7,10 @@ import type { GitCommitish } from '../../git/gitUri'; import { GitUri, unknownGitUri } from '../../git/gitUri'; import { GitReference, GitRevision } from '../../git/models/reference'; import { Logger } from '../../logger'; +import { getLogScope } from '../../logScope'; import { ReferencePicker } from '../../quickpicks/referencePicker'; import { gate } from '../../system/decorators/gate'; -import { debug, getLogScope, log } from '../../system/decorators/log'; +import { debug, log } from '../../system/decorators/log'; import { debounce } from '../../system/function'; import type { LinesChangeEvent } from '../../trackers/gitLineTracker'; import type { FileHistoryView } from '../fileHistoryView'; diff --git a/src/views/viewBase.ts b/src/views/viewBase.ts index 35073df..a7c983e 100644 --- a/src/views/viewBase.ts +++ b/src/views/viewBase.ts @@ -28,8 +28,9 @@ import type { import { configuration, viewsCommonConfigKeys, viewsConfigKeys } from '../configuration'; import type { Container } from '../container'; import { Logger } from '../logger'; +import { getLogScope } from '../logScope'; import { executeCommand } from '../system/command'; -import { debug, getLogScope, log } from '../system/decorators/log'; +import { debug, log } from '../system/decorators/log'; import { once } from '../system/event'; import { debounce } from '../system/function'; import { cancellable, isPromise } from '../system/promise'; diff --git a/src/vsls/guest.ts b/src/vsls/guest.ts index 5769bdf..d42cf92 100644 --- a/src/vsls/guest.ts +++ b/src/vsls/guest.ts @@ -4,7 +4,8 @@ import type { LiveShare, SharedServiceProxy } from '../@types/vsls'; import type { Container } from '../container'; import type { GitCommandOptions } from '../git/commandOptions'; import { Logger } from '../logger'; -import { debug, getLogScope, log } from '../system/decorators/log'; +import { getLogScope } from '../logScope'; +import { debug, log } from '../system/decorators/log'; import { VslsHostService } from './host'; import type { RepositoryProxy, RequestType } from './protocol'; import { GetRepositoriesForUriRequestType, GitCommandRequestType } from './protocol'; diff --git a/src/vsls/host.ts b/src/vsls/host.ts index ac1674e..748e248 100644 --- a/src/vsls/host.ts +++ b/src/vsls/host.ts @@ -4,7 +4,8 @@ import { git } from '@env/providers'; import type { LiveShare, SharedService } from '../@types/vsls'; import type { Container } from '../container'; import { Logger } from '../logger'; -import { debug, getLogScope, log } from '../system/decorators/log'; +import { getLogScope } from '../logScope'; +import { debug, log } from '../system/decorators/log'; import { join } from '../system/iterable'; import { isVslsRoot, normalizePath } from '../system/path'; import type { diff --git a/src/webviews/apps/commitDetails/commitDetails.ts b/src/webviews/apps/commitDetails/commitDetails.ts index ab90428..1f81b10 100644 --- a/src/webviews/apps/commitDetails/commitDetails.ts +++ b/src/webviews/apps/commitDetails/commitDetails.ts @@ -50,7 +50,7 @@ export class CommitDetailsApp extends App> { } override onInitialize() { - this.log(`${this.appName}.onInitialize`); + this.log(`onInitialize()`); this.renderContent(); } @@ -90,7 +90,7 @@ export class CommitDetailsApp extends App> { protected override onMessageReceived(e: MessageEvent) { const msg = e.data as IpcMessage; - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); switch (msg.method) { // case DidChangeRichStateNotificationType.method: diff --git a/src/webviews/apps/home/home.ts b/src/webviews/apps/home/home.ts index 9f1a59d..ee3698e 100644 --- a/src/webviews/apps/home/home.ts +++ b/src/webviews/apps/home/home.ts @@ -85,7 +85,7 @@ export class HomeApp extends App { switch (msg.method) { case DidChangeSubscriptionNotificationType.method: - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); onIpc(DidChangeSubscriptionNotificationType, msg, params => { this.state.subscription = params.subscription; @@ -96,7 +96,7 @@ export class HomeApp extends App { }); break; case DidChangeExtensionEnabledType.method: - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); onIpc(DidChangeExtensionEnabledType, msg, params => { this.state.extensionEnabled = params.extensionEnabled; @@ -104,7 +104,7 @@ export class HomeApp extends App { }); break; case DidChangeConfigurationType.method: - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); onIpc(DidChangeConfigurationType, msg, params => { this.state.plusEnabled = params.plusEnabled; @@ -112,7 +112,7 @@ export class HomeApp extends App { }); break; case DidChangeLayoutType.method: - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); onIpc(DidChangeLayoutType, msg, params => { this.state.layout = params.layout; diff --git a/src/webviews/apps/plus/graph/graph.tsx b/src/webviews/apps/plus/graph/graph.tsx index a3c8605..5790866 100644 --- a/src/webviews/apps/plus/graph/graph.tsx +++ b/src/webviews/apps/plus/graph/graph.tsx @@ -82,7 +82,7 @@ export class GraphApp extends App { const disposables = super.onBind?.() ?? []; // disposables.push(DOM.on(window, 'keyup', e => this.onKeyUp(e))); - this.log(`${this.appName}.onBind`); + this.log(`onBind()`); this.ensureTheming(this.state); @@ -141,7 +141,7 @@ export class GraphApp extends App { protected override onMessageReceived(e: MessageEvent) { const msg = e.data as IpcMessage; - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); switch (msg.method) { case DidChangeNotificationType.method: @@ -215,7 +215,7 @@ export class GraphApp extends App { const newRowsLength = params.rows.length; this.log( - `${this.appName}.onMessageReceived(${msg.id}:${msg.method}): paging in ${newRowsLength} rows into existing ${previousRowsLength} rows at ${params.paging.startingCursor} (last existing row: ${lastId})`, + `onMessageReceived(${msg.id}:${msg.method}): paging in ${newRowsLength} rows into existing ${previousRowsLength} rows at ${params.paging.startingCursor} (last existing row: ${lastId})`, ); rows = []; @@ -224,7 +224,7 @@ export class GraphApp extends App { if (params.paging.startingCursor !== lastId) { this.log( - `${this.appName}.onMessageReceived(${msg.id}:${msg.method}): searching for ${params.paging.startingCursor} in existing rows`, + `onMessageReceived(${msg.id}:${msg.method}): searching for ${params.paging.startingCursor} in existing rows`, ); let i = 0; @@ -233,7 +233,7 @@ export class GraphApp extends App { rows[i++] = row; if (row.sha === params.paging.startingCursor) { this.log( - `${this.appName}.onMessageReceived(${msg.id}:${msg.method}): found ${params.paging.startingCursor} in existing rows`, + `onMessageReceived(${msg.id}:${msg.method}): found ${params.paging.startingCursor} in existing rows`, ); previousRowsLength = i; @@ -256,9 +256,7 @@ export class GraphApp extends App { rows[previousRowsLength + i] = params.rows[i]; } } else { - this.log( - `${this.appName}.onMessageReceived(${msg.id}:${msg.method}): setting to ${params.rows.length} rows`, - ); + this.log(`onMessageReceived(${msg.id}:${msg.method}): setting to ${params.rows.length} rows`); if (params.rows.length === 0) { rows = this.state.rows; @@ -478,7 +476,7 @@ export class GraphApp extends App { } protected override setState(state: State, type?: IpcNotificationType | InternalNotificationType) { - this.log(`${this.appName}.setState`); + this.log(`setState()`); const themingChanged = this.ensureTheming(state); // Avoid calling the base for now, since we aren't using the vscode state diff --git a/src/webviews/apps/plus/timeline/timeline.ts b/src/webviews/apps/plus/timeline/timeline.ts index 49f2ec1..ee4c909 100644 --- a/src/webviews/apps/plus/timeline/timeline.ts +++ b/src/webviews/apps/plus/timeline/timeline.ts @@ -49,7 +49,7 @@ export class TimelineApp extends App { switch (msg.method) { case DidChangeNotificationType.method: - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); onIpc(DidChangeNotificationType, msg, params => { this.state = params.state; @@ -79,11 +79,11 @@ export class TimelineApp extends App { } } - private onPeriodChanged(e: Event, element: HTMLSelectElement) { + private onPeriodChanged(_e: Event, element: HTMLSelectElement) { const value = element.options[element.selectedIndex].value; assertPeriod(value); - this.log(`${this.appName}.onPeriodChanged: name=${element.name}, value=${value}`); + this.log(`onPeriodChanged(): name=${element.name}, value=${value}`); this.sendCommand(UpdatePeriodCommandType, { period: value }); } diff --git a/src/webviews/apps/rebase/rebase.ts b/src/webviews/apps/rebase/rebase.ts index 9d4f8a6..e733f37 100644 --- a/src/webviews/apps/rebase/rebase.ts +++ b/src/webviews/apps/rebase/rebase.ts @@ -323,7 +323,7 @@ class RebaseEditor extends App { switch (msg.method) { case DidChangeNotificationType.method: - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); onIpc(DidChangeNotificationType, msg, params => { this.setState(params.state); diff --git a/src/webviews/apps/shared/appBase.ts b/src/webviews/apps/shared/appBase.ts index a18960c..9e78167 100644 --- a/src/webviews/apps/shared/appBase.ts +++ b/src/webviews/apps/shared/appBase.ts @@ -1,4 +1,6 @@ /*global window document*/ +import { LogLevel } from '../../../constants'; +import { Logger } from '../../../logger'; import { debounce } from '../../../system/function'; import type { IpcCommandType, @@ -42,8 +44,29 @@ export abstract class App { this.state = (window as any).bootstrap; (window as any).bootstrap = undefined; - this.log(`${this.appName}()`); - // this.log(`${this.appName}(${this.state ? JSON.stringify(this.state) : ''})`); + Logger.configure( + { + name: appName, + createChannel: function (name: string) { + return { + name: name, + appendLine: function (value: string) { + console.log(`[${name}] ${value}`); + }, + dispose: function () { + // noop + }, + show: function (_preserveFocus?: boolean) { + // noop + }, + }; + }, + }, + LogLevel.Debug, + ); + + this.log(`ctor()`); + // this.log(`ctor(${this.state ? JSON.stringify(this.state) : ''})`); this._api = acquireVsCodeApi(); @@ -55,7 +78,7 @@ export abstract class App { disposables.push(initializeAndWatchThemeColors()); requestAnimationFrame(() => { - this.log(`${this.appName}.initializing`); + this.log(`ctor(): initializing...`); try { this.onInitialize?.(); @@ -129,7 +152,7 @@ export abstract class App { } protected log(message: string, ...optionalParams: any[]) { - console.log(message, ...optionalParams); + Logger.log(message, ...optionalParams); } protected getState(): State { @@ -141,7 +164,7 @@ export abstract class App { params: IpcMessageParams, ): void { const id = nextIpcId(); - this.log(`${this.appName}.sendCommand(${id}): name=${command.method}`); + this.log(`sendCommand(${id}): name=${command.method}`); this.postMessage({ id: id, method: command.method, params: params }); } @@ -155,7 +178,7 @@ export abstract class App { completion: TCompletion, ): Promise> { const id = nextIpcId(); - this.log(`${this.appName}.sendCommandWithCompletion(${id}): name=${command.method}`); + this.log(`sendCommandWithCompletion(${id}): name=${command.method}`); const promise = new Promise>((resolve, reject) => { let timeout: ReturnType | undefined; diff --git a/src/webviews/apps/shared/appWithConfigBase.ts b/src/webviews/apps/shared/appWithConfigBase.ts index af7cb85..7384c1a 100644 --- a/src/webviews/apps/shared/appWithConfigBase.ts +++ b/src/webviews/apps/shared/appWithConfigBase.ts @@ -70,7 +70,7 @@ export abstract class AppWithConfig extends Ap protected override onMessageReceived(e: MessageEvent) { const msg = e.data as IpcMessage; - this.log(`${this.appName}.onMessageReceived(${msg.id}): name=${msg.method}`); + this.log(`onMessageReceived(${msg.id}): name=${msg.method}`); switch (msg.method) { case DidOpenAnchorNotificationType.method: { @@ -108,7 +108,7 @@ export abstract class AppWithConfig extends Ap } protected onInputBlurred(element: HTMLInputElement) { - this.log(`${this.appName}.onInputBlurred: name=${element.name}, value=${element.value}`); + this.log(`onInputBlurred(${element.name}): value=${element.value})`); const $popup = document.getElementById(`${element.name}.popup`); if ($popup != null) { @@ -191,9 +191,7 @@ export abstract class AppWithConfig extends Ap protected onInputChecked(element: HTMLInputElement) { if (this._updating) return; - this.log( - `${this.appName}.onInputChecked: name=${element.name}, checked=${element.checked}, value=${element.value}`, - ); + this.log(`onInputChecked(${element.name}): checked=${element.checked}, value=${element.value})`); switch (element.dataset.settingType) { case 'object': { @@ -273,7 +271,7 @@ export abstract class AppWithConfig extends Ap } protected onInputFocused(element: HTMLInputElement) { - this.log(`${this.appName}.onInputFocused: name=${element.name}, value=${element.value}`); + this.log(`onInputFocused(${element.name}): value=${element.value}`); const $popup = document.getElementById(`${element.name}.popup`); if ($popup != null) { @@ -292,7 +290,7 @@ export abstract class AppWithConfig extends Ap const value = element.options[element.selectedIndex].value; - this.log(`${this.appName}.onInputSelected: name=${element.name}, value=${value}`); + this.log(`onInputSelected(${element.name}): value=${value}`); this._changes[element.name] = ensureIfBooleanOrNull(value); @@ -302,7 +300,7 @@ export abstract class AppWithConfig extends Ap protected onTokenMouseDown(element: HTMLElement, e: MouseEvent) { if (this._updating) return; - this.log(`${this.appName}.onTokenClicked: id=${element.id}`); + this.log(`onTokenMouseDown(${element.id})`); const setting = element.closest('.setting'); if (setting == null) return; diff --git a/src/webviews/commitDetails/commitDetailsWebviewView.ts b/src/webviews/commitDetails/commitDetailsWebviewView.ts index 3ee01a0..e02a31f 100644 --- a/src/webviews/commitDetails/commitDetailsWebviewView.ts +++ b/src/webviews/commitDetails/commitDetailsWebviewView.ts @@ -28,10 +28,11 @@ import type { GitRevisionReference } from '../../git/models/reference'; import { GitReference } from '../../git/models/reference'; import type { GitRemote } from '../../git/models/remote'; import { Logger } from '../../logger'; +import { getLogScope } from '../../logScope'; import type { ShowInCommitGraphCommandArgs } from '../../plus/webviews/graph/graphWebview'; import { executeCommand, executeCoreCommand } from '../../system/command'; import type { DateTimeFormat } from '../../system/date'; -import { debug, getLogScope, log } from '../../system/decorators/log'; +import { debug, log } from '../../system/decorators/log'; import type { Deferrable } from '../../system/function'; import { debounce } from '../../system/function'; import { map, union } from '../../system/iterable'; diff --git a/src/webviews/webviewViewBase.ts b/src/webviews/webviewViewBase.ts index d90e5a3..88fcc9c 100644 --- a/src/webviews/webviewViewBase.ts +++ b/src/webviews/webviewViewBase.ts @@ -12,8 +12,9 @@ import type { Commands, ContextKeys } from '../constants'; import type { Container } from '../container'; import { setContext } from '../context'; import { Logger } from '../logger'; +import { getLogScope } from '../logScope'; import { executeCommand } from '../system/command'; -import { debug, getLogScope, log, logName } from '../system/decorators/log'; +import { debug, log, logName } from '../system/decorators/log'; import { serialize } from '../system/decorators/serialize'; import type { TrackedUsageFeatures } from '../usageTracker'; import type { IpcMessage, IpcMessageParams, IpcNotificationType, WebviewFocusChangedParams } from './protocol';