@gitkraken/core-gitlens 0.16.3 → 0.16.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -1
- package/dist/git/cache.d.ts +64 -5
- package/dist/git/cache.js +75 -5
- package/dist/git/cache.js.map +1 -1
- package/dist/git/models/branch.d.ts +0 -6
- package/dist/git/models/branch.js.map +1 -1
- package/dist/git/providers/branches.d.ts +65 -1
- package/dist/git/providers/refs.d.ts +3 -2
- package/dist/git/providers/shared/remotes.js +5 -5
- package/dist/git/providers/shared/remotes.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +135 -39
- package/dist/git-cli/providers/branches.js +846 -264
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.js +37 -20
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.js +16 -10
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/contributors.js +3 -3
- package/dist/git-cli/providers/contributors.js.map +1 -1
- package/dist/git-cli/providers/diff.js +15 -12
- package/dist/git-cli/providers/diff.js.map +1 -1
- package/dist/git-cli/providers/graph.js +17 -14
- package/dist/git-cli/providers/graph.js.map +1 -1
- package/dist/git-cli/providers/maintenance.js +3 -3
- package/dist/git-cli/providers/maintenance.js.map +1 -1
- package/dist/git-cli/providers/patch.js +4 -1
- package/dist/git-cli/providers/patch.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +2 -2
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.js +16 -13
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/remotes.js +4 -1
- package/dist/git-cli/providers/remotes.js.map +1 -1
- package/dist/git-cli/providers/revision.js +14 -11
- package/dist/git-cli/providers/revision.js.map +1 -1
- package/dist/git-cli/providers/stash.js +2 -2
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/status.js +7 -7
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/tags.js +6 -3
- package/dist/git-cli/providers/tags.js.map +1 -1
- package/dist/git-cli/providers/worktrees.js +3 -3
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/plus/git-github/providers/github/branches.d.ts +9 -1
- package/dist/plus/git-github/providers/github/branches.js +54 -8
- package/dist/plus/git-github/providers/github/branches.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
- package/dist/plus/integrations/reads/drains.d.ts +1 -0
- package/dist/utils/decorators/log.d.ts +3 -1
- package/dist/utils/decorators/log.js +61 -45
- package/dist/utils/decorators/log.js.map +1 -1
- package/dist/utils/logger.d.ts +15 -1
- package/dist/utils/logger.js +30 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/logger.scoped.d.ts +12 -1
- package/dist/utils/logger.scoped.js +38 -4
- package/dist/utils/logger.scoped.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { getParameters } from "../function.js";
|
|
2
2
|
import { getDurationMilliseconds, hrtime } from "../hrtime.js";
|
|
3
3
|
import { Logger as _logger, customLoggableNameFns, getLoggableName } from "../logger.js";
|
|
4
|
-
import { createLogScope, getLoggableScopeBlock,
|
|
4
|
+
import { createLogScope, getLoggableScopeBlock, logScopeIdGenerator, runInScope } from "../logger.scoped.js";
|
|
5
5
|
import { isPromise } from "../promise.js";
|
|
6
|
+
import { getCurrentScope } from "#env/logScope.js";
|
|
6
7
|
//#region ../utils/src/decorators/log.ts
|
|
7
8
|
const defaultSlowCallWarningThreshold = 1500;
|
|
8
9
|
function logName(fn) {
|
|
@@ -41,7 +42,8 @@ function log(logLevel, options) {
|
|
|
41
42
|
let prefixFn;
|
|
42
43
|
let onlyExit = false;
|
|
43
44
|
let timing = true;
|
|
44
|
-
|
|
45
|
+
let quiet = false;
|
|
46
|
+
if (options != null) ({args: argsFn, when: whenFn, exit: exitFn, prefix: prefixFn, onlyExit = false, timing = true, quiet = false} = options);
|
|
45
47
|
const slowThreshold = typeof timing === "object" ? timing.warnAfter : defaultSlowCallWarningThreshold;
|
|
46
48
|
const timed = timing !== false || typeof onlyExit === "object" && onlyExit.after > 0;
|
|
47
49
|
const logFn = logLevel === "trace" ? _logger.trace : logLevel === "debug" ? _logger.debug : _logger.info;
|
|
@@ -60,18 +62,25 @@ function log(logLevel, options) {
|
|
|
60
62
|
descriptor[fnKey] = function(...args) {
|
|
61
63
|
if (!_logger.enabled() || whenFn != null && !whenFn.apply(this, args)) return fn.apply(this, args);
|
|
62
64
|
const shouldLog = _logger.enabled(logLevel);
|
|
63
|
-
const
|
|
65
|
+
const quietUnder = quiet ? _logger.quietCallsUnder : void 0;
|
|
66
|
+
const exitOnly = onlyExit !== false || quietUnder != null;
|
|
67
|
+
const parentScope = getCurrentScope();
|
|
68
|
+
const prevScopeId = parentScope?.scopeId;
|
|
64
69
|
const scopeId = logScopeIdGenerator.next();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
let prefix;
|
|
71
|
+
if (prefixFn != null) {
|
|
72
|
+
const instanceName = this != null ? getLoggableName(this) : void 0;
|
|
73
|
+
prefix = prefixFn({
|
|
74
|
+
id: scopeId,
|
|
75
|
+
instance: this,
|
|
76
|
+
instanceName: instanceName ?? "",
|
|
77
|
+
name: key,
|
|
78
|
+
prefix: formatPrefix(instanceName, key, scopeId, prevScopeId)
|
|
79
|
+
}, ...args);
|
|
80
|
+
} else {
|
|
81
|
+
prefix = lazyPrefix(this, key, scopeId, prevScopeId);
|
|
82
|
+
if (quietUnder == null) prefix = prefix();
|
|
83
|
+
}
|
|
75
84
|
let loggableParams;
|
|
76
85
|
let paramsResolved = false;
|
|
77
86
|
const resolveParams = () => {
|
|
@@ -81,38 +90,40 @@ function log(logLevel, options) {
|
|
|
81
90
|
}
|
|
82
91
|
return loggableParams;
|
|
83
92
|
};
|
|
84
|
-
|
|
93
|
+
const start = timed || quietUnder != null ? hrtime() : void 0;
|
|
94
|
+
const scope = createLogScope(scopeId, prevScopeId, prefix, parentScope, quietUnder != null && shouldLog ? (scope) => {
|
|
95
|
+
const params = resolveParams();
|
|
96
|
+
const started = ` \u00b7 started ${getDurationMilliseconds(start)}ms earlier`;
|
|
97
|
+
logFn.call(_logger, params ? `${scope.prefix}(${params})${started}` : `${scope.prefix}${started}`);
|
|
98
|
+
} : void 0);
|
|
99
|
+
if (!exitOnly && shouldLog) {
|
|
85
100
|
const params = resolveParams();
|
|
86
|
-
logFn.call(_logger, params ? `${prefix}(${params})` : prefix);
|
|
101
|
+
logFn.call(_logger, params ? `${scope.prefix}(${params})` : scope.prefix);
|
|
87
102
|
}
|
|
88
|
-
if (
|
|
89
|
-
const
|
|
103
|
+
if (exitOnly || timed || exitFn != null) {
|
|
104
|
+
const markLogged = (level) => _logger.markLogged(level, scope);
|
|
90
105
|
const logError = (ex) => {
|
|
91
|
-
|
|
106
|
+
scope.exited();
|
|
107
|
+
const duration = timed ? ` [${getDurationMilliseconds(start)}ms]` : "";
|
|
92
108
|
const exitInfo = scope.getExitInfo();
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
} else _logger.error(ex, prefix, exitInfo?.details ? `failed${exitInfo.details}${duration}` : `failed${duration}`);
|
|
109
|
+
const params = exitOnly ? resolveParams() : void 0;
|
|
110
|
+
markLogged("error");
|
|
111
|
+
_logger.error(ex, params ? `${scope.prefix}(${params})` : scope.prefix, exitInfo?.details ? `failed${exitInfo.details}${duration}` : `failed${duration}`);
|
|
97
112
|
};
|
|
98
113
|
const logResult = (r) => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (start != null) {
|
|
103
|
-
duration = getDurationMilliseconds(start);
|
|
104
|
-
if (duration > slowThreshold) {
|
|
105
|
-
exitLogFn = _logger.warn;
|
|
106
|
-
durationSuffix = ` [*${duration}ms] (slow)`;
|
|
107
|
-
} else {
|
|
108
|
-
exitLogFn = logFn;
|
|
109
|
-
durationSuffix = ` [${duration}ms]`;
|
|
110
|
-
}
|
|
111
|
-
} else {
|
|
112
|
-
durationSuffix = "";
|
|
113
|
-
exitLogFn = logFn;
|
|
114
|
-
}
|
|
114
|
+
scope.exited();
|
|
115
|
+
const duration = start != null ? getDurationMilliseconds(start) : void 0;
|
|
116
|
+
const slow = timed && duration > slowThreshold;
|
|
115
117
|
const exitInfo = scope.getExitInfo();
|
|
118
|
+
const failed = exitFn == null && exitInfo.failed != null;
|
|
119
|
+
if (!slow && exitInfo.failed == null) {
|
|
120
|
+
if (!shouldLog) return;
|
|
121
|
+
const belowAfter = typeof onlyExit === "object" && onlyExit.after > 0 && duration <= onlyExit.after;
|
|
122
|
+
if (quietUnder != null) {
|
|
123
|
+
if (!scope.logged && (duration < quietUnder || belowAfter)) return;
|
|
124
|
+
} else if (belowAfter) return;
|
|
125
|
+
}
|
|
126
|
+
let exitLogFn = slow ? _logger.warn : logFn;
|
|
116
127
|
let exit;
|
|
117
128
|
if (exitFn != null) {
|
|
118
129
|
if (typeof exitFn === "function") try {
|
|
@@ -121,16 +132,14 @@ function log(logLevel, options) {
|
|
|
121
132
|
exit = `@log.exit error: ${ex}`;
|
|
122
133
|
}
|
|
123
134
|
else if (exitFn === true) exit = `returned ${_logger.toLoggable(r)}`;
|
|
124
|
-
} else if (
|
|
135
|
+
} else if (failed) {
|
|
125
136
|
exit = exitInfo.failed;
|
|
126
137
|
exitLogFn = (message, ...params) => _logger.error(null, message, ...params);
|
|
127
138
|
} else exit = "completed";
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
} else exitLogFn.call(_logger, params ? `${prefix}(${params}) ${exit}${exitInfo?.details || ""}${durationSuffix}` : `${prefix} ${exit}${exitInfo?.details || ""}${durationSuffix}`);
|
|
133
|
-
}
|
|
139
|
+
const durationSuffix = !timed ? "" : slow ? ` [*${duration}ms] (slow)` : ` [${duration}ms]`;
|
|
140
|
+
const params = resolveParams();
|
|
141
|
+
markLogged(slow ? "warn" : failed ? "error" : logLevel);
|
|
142
|
+
exitLogFn.call(_logger, params ? `${scope.prefix}(${params}) ${exit}${exitInfo.details || ""}${durationSuffix}` : `${scope.prefix} ${exit}${exitInfo.details || ""}${durationSuffix}`);
|
|
134
143
|
};
|
|
135
144
|
const execute = () => {
|
|
136
145
|
let result;
|
|
@@ -150,6 +159,13 @@ function log(logLevel, options) {
|
|
|
150
159
|
};
|
|
151
160
|
};
|
|
152
161
|
}
|
|
162
|
+
/** Kept outside the decorated call so the scope, which can outlive the call, doesn't hold on to its arguments */
|
|
163
|
+
function lazyPrefix(instance, key, scopeId, prevScopeId) {
|
|
164
|
+
return () => formatPrefix(instance != null ? getLoggableName(instance) : void 0, key, scopeId, prevScopeId);
|
|
165
|
+
}
|
|
166
|
+
function formatPrefix(instanceName, key, scopeId, prevScopeId) {
|
|
167
|
+
return instanceName ? `${getLoggableScopeBlock(scopeId, prevScopeId)} ${instanceName}.${key}` : `${getLoggableScopeBlock(scopeId, prevScopeId)} ${key}`;
|
|
168
|
+
}
|
|
153
169
|
function formatParams(argsFn, args, parameters) {
|
|
154
170
|
if (argsFn === false || !args.length) return void 0;
|
|
155
171
|
if (typeof argsFn === "function") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.js","names":["Logger"],"sources":["../../../../utils/src/decorators/log.ts"],"sourcesContent":["/* oxlint-disable typescript/no-unsafe-return */\nimport { getParameters } from '../function.js';\nimport { getDurationMilliseconds, hrtime } from '../hrtime.js';\nimport type { LogLevel } from '../logger.js';\nimport { customLoggableNameFns, getLoggableName, Logger } from '../logger.js';\nimport {\n\tcreateLogScope,\n\tgetLoggableScopeBlock,\n\tgetScopedLogger,\n\tlogScopeIdGenerator,\n\trunInScope,\n} from '../logger.scoped.js';\nimport { isPromise } from '../promise.js';\n\nexport const defaultSlowCallWarningThreshold = 1500;\n\nexport interface LogContext {\n\tid: number;\n\tinstance: any;\n\tinstanceName: string;\n\tname: string;\n\tprefix: string;\n}\n\ninterface LogOptions<T extends (...args: any[]) => any> {\n\t/** Controls parameter formatting in log output. `false` suppresses all params. A function receives the method args and returns named fields to log (or `false` to suppress). When omitted, params are auto-formatted from parameter names. */\n\targs?: false | ((...args: Parameters<T>) => Record<string, unknown> | false);\n\t/** Conditionally skips logging entirely (scope, timing, everything). Must use a `function` expression (not arrow) — `this` is bound to the class instance via `.apply()`. Annotate `this` with the class type for type safety. */\n\twhen?(this: unknown, ...args: Parameters<T>): boolean;\n\t/** Controls exit/result logging. `true` logs the return value. A function receives the result and returns a custom exit string. */\n\texit?: ((result: PromiseType<ReturnType<T>>) => string) | true;\n\t/** Overrides the log line prefix. Receives a {@link LogContext} and the method args. */\n\tprefix?(context: LogContext, ...args: Parameters<T>): string;\n\t/** Suppresses the entry log line and only logs on exit. `{ after: N }` further suppresses exit unless duration exceeds N ms. */\n\tonlyExit?: true | { after: number };\n\t/** Controls duration timing. `false` disables timing. `{ warnAfter: N }` overrides the slow call warning threshold (default 500ms). */\n\ttiming?: boolean | { warnAfter: number };\n}\n\n// Using Function type to support classes with private/protected constructors\n// oxlint-disable-next-line typescript/no-unsafe-function-type\nexport function logName<T>(fn: (c: T, name: string) => string): (target: Function & { prototype: T }) => void {\n\t// oxlint-disable-next-line typescript/no-unsafe-function-type\n\treturn (target: (abstract new (...args: any[]) => T) | (Function & { prototype: T })): void =>\n\t\tvoid customLoggableNameFns.set(target, fn);\n}\n\n/**\n * Class decorator that adds a `toLoggable()` method to the prototype at runtime,\n * making instances compatible with the `Loggable` interface without requiring the\n * method to appear in the class's structural type.\n *\n * @param fn Optional function returning the content inside the parentheses.\n * Defaults to `id` if the instance has one, otherwise just `ClassName`.\n */\nexport function loggable<T extends object>(fn?: (instance: T) => string) {\n\t// oxlint-disable-next-line typescript/no-unsafe-function-type\n\treturn (target: (abstract new (...args: any[]) => T) | (Function & { prototype: T })): void => {\n\t\ttarget.prototype.toLoggable = function (this: T): string {\n\t\t\tconst name = getLoggableName(this);\n\t\t\tif (fn != null) return `${name}(${fn(this)})`;\n\t\t\treturn name;\n\t\t};\n\t};\n}\n\nexport function info<T extends (...arg: any[]) => any>(\n\toptions?: LogOptions<T>,\n): (_target: any, key: string, descriptor: TypedPropertyDescriptor<T>) => void {\n\treturn log<T>('info', options);\n}\n\nexport function debug<T extends (...arg: any[]) => any>(\n\toptions?: LogOptions<T>,\n): (_target: any, key: string, descriptor: TypedPropertyDescriptor<T>) => void {\n\treturn log<T>('debug', options);\n}\n\nexport function trace<T extends (...arg: any[]) => any>(\n\toptions?: LogOptions<T>,\n): (_target: any, key: string, descriptor: TypedPropertyDescriptor<T>) => void {\n\treturn log<T>('trace', options);\n}\n\ntype PromiseType<T> = T extends Promise<infer U> ? U : T;\n\nfunction log<T extends (...arg: any[]) => any>(\n\tlogLevel: Exclude<LogLevel, 'off' | 'error' | 'warn'>,\n\toptions?: LogOptions<T>,\n): (_target: any, key: string, descriptor: TypedPropertyDescriptor<T>) => void {\n\tlet argsFn: LogOptions<T>['args'] | undefined;\n\tlet whenFn: LogOptions<T>['when'] | undefined;\n\tlet exitFn: LogOptions<T>['exit'] | undefined;\n\tlet prefixFn: LogOptions<T>['prefix'] | undefined;\n\tlet onlyExit: NonNullable<LogOptions<T>['onlyExit']> | false = false;\n\tlet timing: NonNullable<LogOptions<T>['timing']> = true;\n\tif (options != null) {\n\t\t({ args: argsFn, when: whenFn, exit: exitFn, prefix: prefixFn, onlyExit = false, timing = true } = options);\n\t}\n\n\tconst slowThreshold = typeof timing === 'object' ? timing.warnAfter : defaultSlowCallWarningThreshold;\n\tconst timed = timing !== false || (typeof onlyExit === 'object' && onlyExit.after > 0);\n\n\tconst logFn: (message: string, ...params: any[]) => void =\n\t\tlogLevel === 'trace' ? Logger.trace : logLevel === 'debug' ? Logger.debug : Logger.info;\n\n\treturn (_target: any, key: string, descriptor: PropertyDescriptor & Record<string, any>) => {\n\t\t// oxlint-disable-next-line typescript/no-unsafe-function-type\n\t\tlet fn: Function | undefined;\n\t\tlet fnKey: string | undefined;\n\t\tif (typeof descriptor.value === 'function') {\n\t\t\tfn = descriptor.value;\n\t\t\tfnKey = 'value';\n\t\t} else if (typeof descriptor.get === 'function') {\n\t\t\tfn = descriptor.get;\n\t\t\tfnKey = 'get';\n\t\t}\n\t\tif (fn == null || fnKey == null) throw new Error('Not supported');\n\n\t\t// Only extract parameter names for default formatting (when no args option provided)\n\t\tconst parameters = argsFn == null ? getParameters(fn) : [];\n\n\t\tdescriptor[fnKey] = function (this: any, ...args: Parameters<T>) {\n\t\t\t// Always create scope unless logging is completely off (or condition fails)\n\t\t\t// This ensures scope is available for error logging even at lower log levels\n\t\t\tif (!Logger.enabled() || (whenFn != null && !whenFn.apply(this, args))) {\n\t\t\t\treturn fn.apply(this, args);\n\t\t\t}\n\n\t\t\tconst shouldLog = Logger.enabled(logLevel);\n\n\t\t\t// Get parent scope\n\t\t\tconst parentScope = getScopedLogger();\n\t\t\tconst prevScopeId = parentScope?.scopeId;\n\t\t\tconst scopeId = logScopeIdGenerator.next();\n\n\t\t\tconst instanceName = this != null ? getLoggableName(this) : undefined;\n\n\t\t\tlet prefix = instanceName\n\t\t\t\t? `${getLoggableScopeBlock(scopeId, prevScopeId)} ${instanceName}.${key}`\n\t\t\t\t: `${getLoggableScopeBlock(scopeId, prevScopeId)} ${key}`;\n\n\t\t\tif (prefixFn != null) {\n\t\t\t\tprefix = prefixFn(\n\t\t\t\t\t{\n\t\t\t\t\t\tid: scopeId,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t\tinstanceName: instanceName ?? '',\n\t\t\t\t\t\tname: key,\n\t\t\t\t\t\tprefix: prefix,\n\t\t\t\t\t},\n\t\t\t\t\t...args,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst scope = createLogScope(scopeId, prevScopeId, prefix);\n\n\t\t\t// Lazy parameter formatting — deferred until first use to avoid\n\t\t\t// expensive Logger.toLoggable() calls when the log won't be emitted\n\t\t\tlet loggableParams: string | undefined;\n\t\t\tlet paramsResolved = false;\n\t\t\tconst resolveParams = (): string | undefined => {\n\t\t\t\tif (!paramsResolved) {\n\t\t\t\t\tparamsResolved = true;\n\t\t\t\t\tloggableParams = formatParams(argsFn, args, parameters);\n\t\t\t\t}\n\t\t\t\treturn loggableParams;\n\t\t\t};\n\n\t\t\t// For non-onlyExit mode, log entry immediately\n\t\t\tif (!onlyExit && shouldLog) {\n\t\t\t\tconst params = resolveParams();\n\t\t\t\tlogFn.call(Logger, params ? `${prefix}(${params})` : prefix);\n\t\t\t}\n\n\t\t\tif (onlyExit || timed || exitFn != null) {\n\t\t\t\tconst start = timed ? hrtime() : undefined;\n\n\t\t\t\tconst logError = (ex: unknown) => {\n\t\t\t\t\tconst duration = start !== undefined ? ` [${getDurationMilliseconds(start)}ms]` : '';\n\t\t\t\t\tconst exitInfo = scope.getExitInfo();\n\t\t\t\t\tif (onlyExit) {\n\t\t\t\t\t\tconst params = resolveParams();\n\t\t\t\t\t\tLogger.error(\n\t\t\t\t\t\t\tex,\n\t\t\t\t\t\t\tparams ? `${prefix}(${params})` : prefix,\n\t\t\t\t\t\t\texitInfo?.details ? `failed${exitInfo.details}${duration}` : `failed${duration}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tLogger.error(\n\t\t\t\t\t\t\tex,\n\t\t\t\t\t\t\tprefix,\n\t\t\t\t\t\t\texitInfo?.details ? `failed${exitInfo.details}${duration}` : `failed${duration}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst logResult = (r: any) => {\n\t\t\t\t\tlet duration: number | undefined;\n\t\t\t\t\tlet exitLogFn: typeof logFn;\n\t\t\t\t\tlet durationSuffix;\n\t\t\t\t\tif (start != null) {\n\t\t\t\t\t\tduration = getDurationMilliseconds(start);\n\t\t\t\t\t\tif (duration > slowThreshold) {\n\t\t\t\t\t\t\texitLogFn = Logger.warn;\n\t\t\t\t\t\t\tdurationSuffix = ` [*${duration}ms] (slow)`;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\texitLogFn = logFn;\n\t\t\t\t\t\t\tdurationSuffix = ` [${duration}ms]`;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdurationSuffix = '';\n\t\t\t\t\t\texitLogFn = logFn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst exitInfo = scope.getExitInfo();\n\t\t\t\t\tlet exit;\n\t\t\t\t\tif (exitFn != null) {\n\t\t\t\t\t\tif (typeof exitFn === 'function') {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\texit = exitFn(r);\n\t\t\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t\t\texit = `@log.exit error: ${ex}`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (exitFn === true) {\n\t\t\t\t\t\t\texit = `returned ${Logger.toLoggable(r)}`;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (exitInfo?.failed) {\n\t\t\t\t\t\texit = exitInfo.failed;\n\t\t\t\t\t\texitLogFn = (message: string, ...params: any[]) => Logger.error(null, message, ...params);\n\t\t\t\t\t} else {\n\t\t\t\t\t\texit = 'completed';\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only log if: logging at this level, or slow call warning, or error\n\t\t\t\t\tif (shouldLog || exitLogFn !== logFn) {\n\t\t\t\t\t\tconst params = resolveParams();\n\t\t\t\t\t\tif (onlyExit) {\n\t\t\t\t\t\t\tif (onlyExit === true || onlyExit.after === 0 || duration! > onlyExit.after) {\n\t\t\t\t\t\t\t\texitLogFn.call(\n\t\t\t\t\t\t\t\t\tLogger,\n\t\t\t\t\t\t\t\t\tparams\n\t\t\t\t\t\t\t\t\t\t? `${prefix}(${params}) ${exit}${exitInfo?.details || ''}${durationSuffix}`\n\t\t\t\t\t\t\t\t\t\t: `${prefix} ${exit}${exitInfo?.details || ''}${durationSuffix}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\texitLogFn.call(\n\t\t\t\t\t\t\t\tLogger,\n\t\t\t\t\t\t\t\tparams\n\t\t\t\t\t\t\t\t\t? `${prefix}(${params}) ${exit}${exitInfo?.details || ''}${durationSuffix}`\n\t\t\t\t\t\t\t\t\t: `${prefix} ${exit}${exitInfo?.details || ''}${durationSuffix}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tconst execute = () => {\n\t\t\t\t\tlet result;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = fn.apply(this, args);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tlogError(ex);\n\t\t\t\t\t\tthrow ex;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result != null && isPromise(result)) {\n\t\t\t\t\t\tvoid result.then(logResult, logError).catch(() => {});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogResult(result);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn result;\n\t\t\t\t};\n\n\t\t\t\t// Run within scope context\n\t\t\t\treturn runInScope(scope, execute);\n\t\t\t}\n\n\t\t\treturn runInScope(scope, () => fn.apply(this, args));\n\t\t};\n\t};\n}\n\nfunction formatParams<T extends (...args: any[]) => any>(\n\targsFn: LogOptions<T>['args'] | undefined,\n\targs: Parameters<T>,\n\tparameters: string[],\n): string | undefined {\n\tif (argsFn === false || !args.length) return undefined;\n\n\t// Function form: call it and format the returned Record\n\tif (typeof argsFn === 'function') {\n\t\tconst result = argsFn(...args);\n\t\tif (result === false) return undefined;\n\n\t\tlet formatted = '';\n\t\tfor (const [name, value] of Object.entries(result)) {\n\t\t\tif (formatted.length) {\n\t\t\t\tformatted += ', ';\n\t\t\t}\n\t\t\tformatted += `${name}=${Logger.toLoggable(value, name)}`;\n\t\t}\n\t\treturn formatted || undefined;\n\t}\n\n\t// Default: use parameter names from getParameters()\n\tlet formatted = '';\n\tlet paramIndex = -1;\n\tfor (const paramValue of args as unknown[]) {\n\t\tconst paramName = parameters[++paramIndex];\n\t\tif (formatted.length) {\n\t\t\tformatted += ', ';\n\t\t}\n\t\tformatted += paramName\n\t\t\t? `${paramName}=${Logger.toLoggable(paramValue, paramName)}`\n\t\t\t: Logger.toLoggable(paramValue);\n\t}\n\treturn formatted || undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"log.js","names":["Logger"],"sources":["../../../../utils/src/decorators/log.ts"],"sourcesContent":["/* oxlint-disable typescript/no-unsafe-return */\nimport { getCurrentScope } from '#env/logScope.js';\nimport { getParameters } from '../function.js';\nimport { getDurationMilliseconds, hrtime } from '../hrtime.js';\nimport type { LogLevel } from '../logger.js';\nimport { customLoggableNameFns, getLoggableName, Logger } from '../logger.js';\nimport type { ScopedLogger } from '../logger.scoped.js';\nimport { createLogScope, getLoggableScopeBlock, logScopeIdGenerator, runInScope } from '../logger.scoped.js';\nimport { isPromise } from '../promise.js';\n\nexport const defaultSlowCallWarningThreshold = 1500;\n\nexport interface LogContext {\n\tid: number;\n\tinstance: any;\n\tinstanceName: string;\n\tname: string;\n\tprefix: string;\n}\n\ninterface LogOptions<T extends (...args: any[]) => any> {\n\t/** Controls parameter formatting in log output. `false` suppresses all params. A function receives the method args and returns named fields to log (or `false` to suppress). When omitted, params are auto-formatted from parameter names. */\n\targs?: false | ((...args: Parameters<T>) => Record<string, unknown> | false);\n\t/** Conditionally skips logging entirely (scope, timing, everything). Must use a `function` expression (not arrow) — `this` is bound to the class instance via `.apply()`. Annotate `this` with the class type for type safety. */\n\twhen?(this: unknown, ...args: Parameters<T>): boolean;\n\t/** Controls exit/result logging. `true` logs the return value. A function receives the result and returns a custom exit string. */\n\texit?: ((result: PromiseType<ReturnType<T>>) => string) | true;\n\t/** Overrides the log line prefix. Receives a {@link LogContext} and the method args. */\n\tprefix?(context: LogContext, ...args: Parameters<T>): string;\n\t/** Suppresses the entry log line and only logs on exit. `{ after: N }` further suppresses exit unless duration exceeds N ms, the call ran slow, or it failed. */\n\tonlyExit?: true | { after: number };\n\t/** Marks a read whose only work worth logging shows up as lines of its own (e.g. git commands) and that changes no state silently. When the logger sets `quietCallsUnder`, it writes no entry line up front, and logs only if it took that long, failed, ran slow, or something was logged while it ran. */\n\tquiet?: true;\n\t/** Controls duration timing. `false` disables timing. `{ warnAfter: N }` overrides the slow call warning threshold (default 500ms). */\n\ttiming?: boolean | { warnAfter: number };\n}\n\n// Using Function type to support classes with private/protected constructors\n// oxlint-disable-next-line typescript/no-unsafe-function-type\nexport function logName<T>(fn: (c: T, name: string) => string): (target: Function & { prototype: T }) => void {\n\t// oxlint-disable-next-line typescript/no-unsafe-function-type\n\treturn (target: (abstract new (...args: any[]) => T) | (Function & { prototype: T })): void =>\n\t\tvoid customLoggableNameFns.set(target, fn);\n}\n\n/**\n * Class decorator that adds a `toLoggable()` method to the prototype at runtime,\n * making instances compatible with the `Loggable` interface without requiring the\n * method to appear in the class's structural type.\n *\n * @param fn Optional function returning the content inside the parentheses.\n * Defaults to `id` if the instance has one, otherwise just `ClassName`.\n */\nexport function loggable<T extends object>(fn?: (instance: T) => string) {\n\t// oxlint-disable-next-line typescript/no-unsafe-function-type\n\treturn (target: (abstract new (...args: any[]) => T) | (Function & { prototype: T })): void => {\n\t\ttarget.prototype.toLoggable = function (this: T): string {\n\t\t\tconst name = getLoggableName(this);\n\t\t\tif (fn != null) return `${name}(${fn(this)})`;\n\t\t\treturn name;\n\t\t};\n\t};\n}\n\nexport function info<T extends (...arg: any[]) => any>(\n\toptions?: LogOptions<T>,\n): (_target: any, key: string, descriptor: TypedPropertyDescriptor<T>) => void {\n\treturn log<T>('info', options);\n}\n\nexport function debug<T extends (...arg: any[]) => any>(\n\toptions?: LogOptions<T>,\n): (_target: any, key: string, descriptor: TypedPropertyDescriptor<T>) => void {\n\treturn log<T>('debug', options);\n}\n\nexport function trace<T extends (...arg: any[]) => any>(\n\toptions?: LogOptions<T>,\n): (_target: any, key: string, descriptor: TypedPropertyDescriptor<T>) => void {\n\treturn log<T>('trace', options);\n}\n\ntype PromiseType<T> = T extends Promise<infer U> ? U : T;\n\nfunction log<T extends (...arg: any[]) => any>(\n\tlogLevel: Exclude<LogLevel, 'off' | 'error' | 'warn'>,\n\toptions?: LogOptions<T>,\n): (_target: any, key: string, descriptor: TypedPropertyDescriptor<T>) => void {\n\tlet argsFn: LogOptions<T>['args'] | undefined;\n\tlet whenFn: LogOptions<T>['when'] | undefined;\n\tlet exitFn: LogOptions<T>['exit'] | undefined;\n\tlet prefixFn: LogOptions<T>['prefix'] | undefined;\n\tlet onlyExit: NonNullable<LogOptions<T>['onlyExit']> | false = false;\n\tlet timing: NonNullable<LogOptions<T>['timing']> = true;\n\tlet quiet = false;\n\tif (options != null) {\n\t\t({\n\t\t\targs: argsFn,\n\t\t\twhen: whenFn,\n\t\t\texit: exitFn,\n\t\t\tprefix: prefixFn,\n\t\t\tonlyExit = false,\n\t\t\ttiming = true,\n\t\t\tquiet = false,\n\t\t} = options);\n\t}\n\n\tconst slowThreshold = typeof timing === 'object' ? timing.warnAfter : defaultSlowCallWarningThreshold;\n\tconst timed = timing !== false || (typeof onlyExit === 'object' && onlyExit.after > 0);\n\n\tconst logFn: (message: string, ...params: any[]) => void =\n\t\tlogLevel === 'trace' ? Logger.trace : logLevel === 'debug' ? Logger.debug : Logger.info;\n\n\treturn (_target: any, key: string, descriptor: PropertyDescriptor & Record<string, any>) => {\n\t\t// oxlint-disable-next-line typescript/no-unsafe-function-type\n\t\tlet fn: Function | undefined;\n\t\tlet fnKey: string | undefined;\n\t\tif (typeof descriptor.value === 'function') {\n\t\t\tfn = descriptor.value;\n\t\t\tfnKey = 'value';\n\t\t} else if (typeof descriptor.get === 'function') {\n\t\t\tfn = descriptor.get;\n\t\t\tfnKey = 'get';\n\t\t}\n\t\tif (fn == null || fnKey == null) throw new Error('Not supported');\n\n\t\t// Only extract parameter names for default formatting (when no args option provided)\n\t\tconst parameters = argsFn == null ? getParameters(fn) : [];\n\n\t\tdescriptor[fnKey] = function (this: any, ...args: Parameters<T>) {\n\t\t\t// Always create scope unless logging is completely off (or condition fails)\n\t\t\t// This ensures scope is available for error logging even at lower log levels\n\t\t\tif (!Logger.enabled() || (whenFn != null && !whenFn.apply(this, args))) {\n\t\t\t\treturn fn.apply(this, args);\n\t\t\t}\n\n\t\t\tconst shouldLog = Logger.enabled(logLevel);\n\t\t\tconst quietUnder = quiet ? Logger.quietCallsUnder : undefined;\n\t\t\tconst exitOnly = onlyExit !== false || quietUnder != null;\n\n\t\t\tconst parentScope = getCurrentScope();\n\t\t\tconst prevScopeId = parentScope?.scopeId;\n\t\t\tconst scopeId = logScopeIdGenerator.next();\n\n\t\t\t// A quieted call builds its default prefix on first use, since it usually writes nothing. Any other call, and any\n\t\t\t// custom prefix, is built before the call runs, so it reflects state as it was when the call started\n\t\t\tlet prefix: string | (() => string);\n\t\t\tif (prefixFn != null) {\n\t\t\t\tconst instanceName = this != null ? getLoggableName(this) : undefined;\n\t\t\t\tprefix = prefixFn(\n\t\t\t\t\t{\n\t\t\t\t\t\tid: scopeId,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t\tinstanceName: instanceName ?? '',\n\t\t\t\t\t\tname: key,\n\t\t\t\t\t\tprefix: formatPrefix(instanceName, key, scopeId, prevScopeId),\n\t\t\t\t\t},\n\t\t\t\t\t...args,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tprefix = lazyPrefix(this, key, scopeId, prevScopeId);\n\t\t\t\tif (quietUnder == null) {\n\t\t\t\t\tprefix = prefix();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Lazy parameter formatting — deferred until first use to avoid\n\t\t\t// expensive Logger.toLoggable() calls when the log won't be emitted\n\t\t\tlet loggableParams: string | undefined;\n\t\t\tlet paramsResolved = false;\n\t\t\tconst resolveParams = (): string | undefined => {\n\t\t\t\tif (!paramsResolved) {\n\t\t\t\t\tparamsResolved = true;\n\t\t\t\t\tloggableParams = formatParams(argsFn, args, parameters);\n\t\t\t\t}\n\t\t\t\treturn loggableParams;\n\t\t\t};\n\n\t\t\tconst start = timed || quietUnder != null ? hrtime() : undefined;\n\n\t\t\t// A quieted call has no entry line, so when a line is first written inside it (e.g. a git command), it writes\n\t\t\t// its entry then, ahead of that line, so the log still shows the cause before what it caused\n\t\t\tconst writeLateEntry =\n\t\t\t\tquietUnder != null && shouldLog\n\t\t\t\t\t? (scope: ScopedLogger) => {\n\t\t\t\t\t\t\tconst params = resolveParams();\n\t\t\t\t\t\t\tconst started = ` \\u00b7 started ${getDurationMilliseconds(start!)}ms earlier`;\n\t\t\t\t\t\t\tlogFn.call(\n\t\t\t\t\t\t\t\tLogger,\n\t\t\t\t\t\t\t\tparams ? `${scope.prefix}(${params})${started}` : `${scope.prefix}${started}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined;\n\n\t\t\tconst scope = createLogScope(scopeId, prevScopeId, prefix, parentScope, writeLateEntry);\n\n\t\t\tif (!exitOnly && shouldLog) {\n\t\t\t\tconst params = resolveParams();\n\t\t\t\tlogFn.call(Logger, params ? `${scope.prefix}(${params})` : scope.prefix);\n\t\t\t}\n\n\t\t\tif (exitOnly || timed || exitFn != null) {\n\t\t\t\t// An async exit can run outside this call's scope (the browser tracks scope only synchronously), so the\n\t\t\t\t// exit line marks the call directly rather than relying on the current scope. The call has returned, so\n\t\t\t\t// this marks only its callers: it writes no late entry of its own just ahead of its exit line\n\t\t\t\tconst markLogged = (level: Exclude<LogLevel, 'off'>) => Logger.markLogged(level, scope);\n\n\t\t\t\tconst logError = (ex: unknown) => {\n\t\t\t\t\tscope.exited();\n\t\t\t\t\tconst duration = timed ? ` [${getDurationMilliseconds(start!)}ms]` : '';\n\t\t\t\t\tconst exitInfo = scope.getExitInfo();\n\t\t\t\t\t// With no entry line, the exit line carries the arguments\n\t\t\t\t\tconst params = exitOnly ? resolveParams() : undefined;\n\t\t\t\t\tmarkLogged('error');\n\t\t\t\t\tLogger.error(\n\t\t\t\t\t\tex,\n\t\t\t\t\t\tparams ? `${scope.prefix}(${params})` : scope.prefix,\n\t\t\t\t\t\texitInfo?.details ? `failed${exitInfo.details}${duration}` : `failed${duration}`,\n\t\t\t\t\t);\n\t\t\t\t};\n\n\t\t\t\tconst logResult = (r: any) => {\n\t\t\t\t\tscope.exited();\n\t\t\t\t\tconst duration = start != null ? getDurationMilliseconds(start) : undefined;\n\t\t\t\t\tconst slow = timed && duration! > slowThreshold;\n\t\t\t\t\tconst exitInfo = scope.getExitInfo();\n\t\t\t\t\tconst failed = exitFn == null && exitInfo.failed != null;\n\n\t\t\t\t\t// Slow and failed calls always log (at warn and error); anything else only when this level is\n\t\t\t\t\t// logged, and then only if the quiet-calls policy or `onlyExit.after` doesn't drop it\n\t\t\t\t\tif (!slow && exitInfo.failed == null) {\n\t\t\t\t\t\tif (!shouldLog) return;\n\n\t\t\t\t\t\tconst belowAfter =\n\t\t\t\t\t\t\ttypeof onlyExit === 'object' && onlyExit.after > 0 && duration! <= onlyExit.after;\n\t\t\t\t\t\tif (quietUnder != null) {\n\t\t\t\t\t\t\tif (!scope.logged && (duration! < quietUnder || belowAfter)) return;\n\t\t\t\t\t\t} else if (belowAfter) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet exitLogFn: (message: string, ...params: any[]) => void = slow ? Logger.warn : logFn;\n\t\t\t\t\tlet exit;\n\t\t\t\t\tif (exitFn != null) {\n\t\t\t\t\t\tif (typeof exitFn === 'function') {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\texit = exitFn(r);\n\t\t\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t\t\texit = `@log.exit error: ${ex}`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (exitFn === true) {\n\t\t\t\t\t\t\texit = `returned ${Logger.toLoggable(r)}`;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (failed) {\n\t\t\t\t\t\texit = exitInfo.failed;\n\t\t\t\t\t\texitLogFn = (message: string, ...params: any[]) => Logger.error(null, message, ...params);\n\t\t\t\t\t} else {\n\t\t\t\t\t\texit = 'completed';\n\t\t\t\t\t}\n\n\t\t\t\t\tconst durationSuffix = !timed ? '' : slow ? ` [*${duration}ms] (slow)` : ` [${duration}ms]`;\n\t\t\t\t\tconst params = resolveParams();\n\t\t\t\t\tmarkLogged(slow ? 'warn' : failed ? 'error' : logLevel);\n\t\t\t\t\texitLogFn.call(\n\t\t\t\t\t\tLogger,\n\t\t\t\t\t\tparams\n\t\t\t\t\t\t\t? `${scope.prefix}(${params}) ${exit}${exitInfo.details || ''}${durationSuffix}`\n\t\t\t\t\t\t\t: `${scope.prefix} ${exit}${exitInfo.details || ''}${durationSuffix}`,\n\t\t\t\t\t);\n\t\t\t\t};\n\n\t\t\t\tconst execute = () => {\n\t\t\t\t\tlet result;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = fn.apply(this, args);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tlogError(ex);\n\t\t\t\t\t\tthrow ex;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result != null && isPromise(result)) {\n\t\t\t\t\t\tvoid result.then(logResult, logError).catch(() => {});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogResult(result);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn result;\n\t\t\t\t};\n\n\t\t\t\t// Run within scope context\n\t\t\t\treturn runInScope(scope, execute);\n\t\t\t}\n\n\t\t\treturn runInScope(scope, () => fn.apply(this, args));\n\t\t};\n\t};\n}\n\n/** Kept outside the decorated call so the scope, which can outlive the call, doesn't hold on to its arguments */\nfunction lazyPrefix(instance: unknown, key: string, scopeId: number, prevScopeId: number | undefined): () => string {\n\treturn () => formatPrefix(instance != null ? getLoggableName(instance) : undefined, key, scopeId, prevScopeId);\n}\n\nfunction formatPrefix(\n\tinstanceName: string | undefined,\n\tkey: string,\n\tscopeId: number,\n\tprevScopeId: number | undefined,\n): string {\n\treturn instanceName\n\t\t? `${getLoggableScopeBlock(scopeId, prevScopeId)} ${instanceName}.${key}`\n\t\t: `${getLoggableScopeBlock(scopeId, prevScopeId)} ${key}`;\n}\n\nfunction formatParams<T extends (...args: any[]) => any>(\n\targsFn: LogOptions<T>['args'] | undefined,\n\targs: Parameters<T>,\n\tparameters: string[],\n): string | undefined {\n\tif (argsFn === false || !args.length) return undefined;\n\n\t// Function form: call it and format the returned Record\n\tif (typeof argsFn === 'function') {\n\t\tconst result = argsFn(...args);\n\t\tif (result === false) return undefined;\n\n\t\tlet formatted = '';\n\t\tfor (const [name, value] of Object.entries(result)) {\n\t\t\tif (formatted.length) {\n\t\t\t\tformatted += ', ';\n\t\t\t}\n\t\t\tformatted += `${name}=${Logger.toLoggable(value, name)}`;\n\t\t}\n\t\treturn formatted || undefined;\n\t}\n\n\t// Default: use parameter names from getParameters()\n\tlet formatted = '';\n\tlet paramIndex = -1;\n\tfor (const paramValue of args as unknown[]) {\n\t\tconst paramName = parameters[++paramIndex];\n\t\tif (formatted.length) {\n\t\t\tformatted += ', ';\n\t\t}\n\t\tformatted += paramName\n\t\t\t? `${paramName}=${Logger.toLoggable(paramValue, paramName)}`\n\t\t\t: Logger.toLoggable(paramValue);\n\t}\n\treturn formatted || undefined;\n}\n"],"mappings":"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"}
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -31,10 +31,19 @@ export interface LogChannel {
|
|
|
31
31
|
warn(message: string, ...args: any[]): void;
|
|
32
32
|
error(error: string | Error, ...args: any[]): void;
|
|
33
33
|
}
|
|
34
|
+
export interface LoggerOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Quiets calls decorated with `quiet: true` (reads that mostly hit a cache): no entry line, and an exit line only
|
|
37
|
+
* when the call took at least this many milliseconds, failed, or wrote a line while it ran (e.g. ran a git command).
|
|
38
|
+
* A quieted call that writes nothing never formats its arguments. Unset, every call logs its entry and exit.
|
|
39
|
+
*/
|
|
40
|
+
quietCallsUnder?: number;
|
|
41
|
+
}
|
|
34
42
|
declare class Logger {
|
|
35
43
|
#private;
|
|
36
|
-
configure(provider: LogChannelProvider, debugging?: boolean): void;
|
|
44
|
+
configure(provider: LogChannelProvider, debugging?: boolean, options?: LoggerOptions): void;
|
|
37
45
|
enabled(level?: Exclude<LogLevel, 'off'>): boolean;
|
|
46
|
+
get quietCallsUnder(): number | undefined;
|
|
38
47
|
get isDebugging(): boolean;
|
|
39
48
|
get logLevel(): LogLevel;
|
|
40
49
|
get timestamp(): string;
|
|
@@ -51,6 +60,11 @@ declare class Logger {
|
|
|
51
60
|
showOutputChannel(preserveFocus?: boolean): void;
|
|
52
61
|
toLoggable(o: any, name?: string): string;
|
|
53
62
|
sanitize(key: string, value: unknown): string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* @internal Records that a line at `level` was written for `scope`'s call, as a line written through the logger
|
|
65
|
+
* would; the `@log` decorator uses it for an exit line, which can run outside its call's scope
|
|
66
|
+
*/
|
|
67
|
+
markLogged(level: Exclude<LogLevel, 'off'>, scope: ScopedLogger): void;
|
|
54
68
|
}
|
|
55
69
|
declare const _logger: Logger;
|
|
56
70
|
export declare const customLoggableNameFns: WeakMap<object, (instance: any, name: string) => string>;
|
package/dist/utils/logger.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { padOrTruncateEnd } from "./string.js";
|
|
2
|
+
import { getCurrentScope } from "#env/logScope.js";
|
|
2
3
|
//#region ../utils/src/logger.ts
|
|
3
4
|
const isoTRegex = /T/;
|
|
4
5
|
const stackCallerRegex = /.*\s*?at\s(.+?)\s/;
|
|
@@ -19,7 +20,8 @@ const defaultSanitizeKeys = [
|
|
|
19
20
|
var Logger = class {
|
|
20
21
|
#output;
|
|
21
22
|
#provider;
|
|
22
|
-
configure(provider, debugging = false) {
|
|
23
|
+
configure(provider, debugging = false, options) {
|
|
24
|
+
this.#quietCallsUnder = options?.quietCallsUnder;
|
|
23
25
|
this.#provider = {
|
|
24
26
|
...provider,
|
|
25
27
|
sanitizeKeys: /* @__PURE__ */ new Set([...defaultSanitizeKeys, ...provider.sanitizeKeys ?? []])
|
|
@@ -37,6 +39,10 @@ var Logger = class {
|
|
|
37
39
|
if (level == null) return true;
|
|
38
40
|
return this.#level <= toOrderedLevel(level);
|
|
39
41
|
}
|
|
42
|
+
#quietCallsUnder;
|
|
43
|
+
get quietCallsUnder() {
|
|
44
|
+
return this.#quietCallsUnder;
|
|
45
|
+
}
|
|
40
46
|
#isDebugging = false;
|
|
41
47
|
get isDebugging() {
|
|
42
48
|
return this.#isDebugging;
|
|
@@ -50,6 +56,7 @@ var Logger = class {
|
|
|
50
56
|
}
|
|
51
57
|
trace(scopeOrMessage, ...params) {
|
|
52
58
|
if ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Trace) && !this.isDebugging) return;
|
|
59
|
+
this.#markScopeLogged(OrderedLevel.Trace, typeof scopeOrMessage === "string" ? void 0 : scopeOrMessage);
|
|
53
60
|
let message;
|
|
54
61
|
if (typeof scopeOrMessage === "string") message = scopeOrMessage;
|
|
55
62
|
else {
|
|
@@ -61,6 +68,7 @@ var Logger = class {
|
|
|
61
68
|
}
|
|
62
69
|
debug(scopeOrMessage, ...params) {
|
|
63
70
|
if ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Debug) && !this.isDebugging) return;
|
|
71
|
+
this.#markScopeLogged(OrderedLevel.Debug, typeof scopeOrMessage === "string" ? void 0 : scopeOrMessage);
|
|
64
72
|
let message;
|
|
65
73
|
if (typeof scopeOrMessage === "string") message = scopeOrMessage;
|
|
66
74
|
else {
|
|
@@ -72,6 +80,7 @@ var Logger = class {
|
|
|
72
80
|
}
|
|
73
81
|
info(scopeOrMessage, ...params) {
|
|
74
82
|
if ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Info) && !this.isDebugging) return;
|
|
83
|
+
this.#markScopeLogged(OrderedLevel.Info, typeof scopeOrMessage === "string" ? void 0 : scopeOrMessage);
|
|
75
84
|
let message;
|
|
76
85
|
if (typeof scopeOrMessage === "string") message = scopeOrMessage;
|
|
77
86
|
else {
|
|
@@ -83,6 +92,7 @@ var Logger = class {
|
|
|
83
92
|
}
|
|
84
93
|
warn(scopeOrMessage, ...params) {
|
|
85
94
|
if ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Warn) && !this.isDebugging) return;
|
|
95
|
+
this.#markScopeLogged(OrderedLevel.Warn, typeof scopeOrMessage === "string" ? void 0 : scopeOrMessage);
|
|
86
96
|
let message;
|
|
87
97
|
if (typeof scopeOrMessage === "string") message = scopeOrMessage;
|
|
88
98
|
else {
|
|
@@ -94,6 +104,7 @@ var Logger = class {
|
|
|
94
104
|
}
|
|
95
105
|
error(ex, scopeOrMessage, ...params) {
|
|
96
106
|
if ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Error) && !this.isDebugging) return;
|
|
107
|
+
this.#markScopeLogged(OrderedLevel.Error, scopeOrMessage == null || typeof scopeOrMessage === "string" ? void 0 : scopeOrMessage);
|
|
97
108
|
let message;
|
|
98
109
|
if (scopeOrMessage == null || typeof scopeOrMessage === "string") message = scopeOrMessage;
|
|
99
110
|
else message = `${scopeOrMessage.prefix} ${params.shift() ?? ""}`;
|
|
@@ -155,6 +166,24 @@ var Logger = class {
|
|
|
155
166
|
if (this.#provider.hash != null) return `<${sanitizeKey}:${this.#provider.hash(typeof value === "string" ? value : JSON.stringify(value))}>`;
|
|
156
167
|
return `<${sanitizeKey}>`;
|
|
157
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* @internal Records that a line at `level` was written for `scope`'s call, as a line written through the logger
|
|
171
|
+
* would; the `@log` decorator uses it for an exit line, which can run outside its call's scope
|
|
172
|
+
*/
|
|
173
|
+
markLogged(level, scope) {
|
|
174
|
+
if (!this.#countsAsLogged(toOrderedLevel(level))) return;
|
|
175
|
+
scope.markLogged();
|
|
176
|
+
}
|
|
177
|
+
/** Records that a line was written inside the call (and so every call above it), so a quieted call still logs its exit */
|
|
178
|
+
#markScopeLogged(level, scope) {
|
|
179
|
+
if (!this.#countsAsLogged(level)) return;
|
|
180
|
+
getCurrentScope()?.markLogged();
|
|
181
|
+
scope?.markLogged();
|
|
182
|
+
}
|
|
183
|
+
/** A line only the debugger console shows (`isDebugging` bypasses the channel's level) doesn't count */
|
|
184
|
+
#countsAsLogged(level) {
|
|
185
|
+
return this.#quietCallsUnder != null && this.#level !== OrderedLevel.Off && this.#level <= level;
|
|
186
|
+
}
|
|
158
187
|
#toLoggableParams(debugOnly, params) {
|
|
159
188
|
if (params.length === 0 || debugOnly && (this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Debug) && !this.isDebugging) return "";
|
|
160
189
|
const loggableParams = params.map((p) => this.toLoggable(p)).join(", ");
|
package/dist/utils/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","names":[],"sources":["../../../utils/src/logger.ts"],"sourcesContent":["import type { ScopedLogger } from './logger.scoped.js';\nimport { padOrTruncateEnd } from './string.js';\nimport type { RequireSome } from './types.js';\n\nconst isoTRegex = /T/;\nconst stackCallerRegex = /.*\\s*?at\\s(.+?)\\s/;\nconst leadingUnderscoreRegex = /^_+/;\n\nexport type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport const OrderedLevel = {\n\tOff: 0,\n\tTrace: 1,\n\tDebug: 2,\n\tInfo: 3,\n\tWarn: 4,\n\tError: 5,\n} as const;\nexport type OrderedLevel = (typeof OrderedLevel)[keyof typeof OrderedLevel];\n\nexport interface LogChannelProvider {\n\treadonly name: string;\n\tcreateChannel(name: string): LogChannel;\n\ttoLoggable?(o: unknown): string | undefined;\n\thash?(data: string): string;\n\n\tsanitizeKeys?: Set<string>;\n}\n\nexport interface LogChannel {\n\treadonly name: string;\n\treadonly logLevel: OrderedLevel;\n\treadonly onDidChangeLogLevel?: (listener: (level: OrderedLevel) => void) => { dispose(): void };\n\n\tdispose?(): void;\n\tshow?(preserveFocus?: boolean): void;\n\n\ttrace(message: string, ...args: any[]): void;\n\tdebug(message: string, ...args: any[]): void;\n\tinfo(message: string, ...args: any[]): void;\n\twarn(message: string, ...args: any[]): void;\n\terror(error: string | Error, ...args: any[]): void;\n}\n\nconst defaultSanitizeKeys = ['accessToken', 'password', 'token'];\n\nclass Logger {\n\t#output: LogChannel | undefined;\n\t#provider: RequireSome<LogChannelProvider, 'sanitizeKeys'> | undefined;\n\n\tconfigure(provider: LogChannelProvider, debugging: boolean = false): void {\n\t\tthis.#provider = {\n\t\t\t...provider,\n\t\t\tsanitizeKeys: new Set([...defaultSanitizeKeys, ...(provider.sanitizeKeys ?? [])]),\n\t\t};\n\n\t\tthis.#isDebugging = debugging;\n\n\t\t// Create output channel and sync with the host's log level\n\t\tthis.#output = provider.createChannel(provider.name);\n\t\tthis.#level = this.#output.logLevel;\n\t\tthis.#output.onDidChangeLogLevel?.(level => {\n\t\t\tthis.#level = level;\n\t\t});\n\t}\n\n\tenabled(level?: Exclude<LogLevel, 'off'>): boolean {\n\t\tif (this.isDebugging) return true;\n\t\tif (this.#level === OrderedLevel.Off) return false;\n\t\tif (level == null) return true;\n\n\t\treturn this.#level <= toOrderedLevel(level);\n\t}\n\n\t#isDebugging = false;\n\tget isDebugging(): boolean {\n\t\treturn this.#isDebugging;\n\t}\n\n\t#level: OrderedLevel = OrderedLevel.Off;\n\tget logLevel(): LogLevel {\n\t\treturn toFriendlyLogLevel(this.#level);\n\t}\n\n\tget timestamp(): string {\n\t\treturn `[${new Date().toISOString().replace(isoTRegex, ' ').slice(0, -1)}]`;\n\t}\n\n\ttrace(message: string, ...params: any[]): void;\n\ttrace(scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n\ttrace(scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Trace) && !this.isDebugging) return;\n\n\t\tlet message;\n\t\tif (typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = params.shift();\n\n\t\t\tif (scopeOrMessage != null) {\n\t\t\t\tmessage = `${scopeOrMessage.prefix} ${message ?? ''}`;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tconsole.debug(`[${padOrTruncateEnd(this.#provider!.name, 13)}]`, this.timestamp, message ?? '', ...params);\n\t\t}\n\t\tthis.#output?.trace(` ${message ?? ''}${this.#toLoggableParams(true, params)}`);\n\t}\n\n\tdebug(message: string, ...params: any[]): void;\n\tdebug(scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n\tdebug(scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Debug) && !this.isDebugging) return;\n\n\t\tlet message;\n\t\tif (typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = params.shift();\n\n\t\t\tif (scopeOrMessage != null) {\n\t\t\t\tmessage = `${scopeOrMessage.prefix} ${message ?? ''}`;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tconsole.debug(`[${padOrTruncateEnd(this.#provider!.name, 13)}]`, this.timestamp, message ?? '', ...params);\n\t\t}\n\t\tthis.#output?.debug(` ${message ?? ''}${this.#toLoggableParams(false, params)}`);\n\t}\n\n\tinfo(message: string, ...params: any[]): void;\n\tinfo(scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n\tinfo(scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Info) && !this.isDebugging) return;\n\n\t\tlet message;\n\t\tif (typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = params.shift();\n\n\t\t\tif (scopeOrMessage != null) {\n\t\t\t\tmessage = `${scopeOrMessage.prefix} ${message ?? ''}`;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tconsole.info(`[${padOrTruncateEnd(this.#provider!.name, 13)}]`, this.timestamp, message ?? '', ...params);\n\t\t}\n\t\tthis.#output?.info(` ${message ?? ''}${this.#toLoggableParams(false, params)}`);\n\t}\n\n\twarn(message: string, ...params: any[]): void;\n\twarn(scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n\twarn(scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Warn) && !this.isDebugging) return;\n\n\t\tlet message;\n\t\tif (typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = params.shift();\n\n\t\t\tif (scopeOrMessage != null) {\n\t\t\t\tmessage = `${scopeOrMessage.prefix} ${message ?? ''}`;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tconsole.warn(`[${padOrTruncateEnd(this.#provider!.name, 13)}]`, this.timestamp, message ?? '', ...params);\n\t\t}\n\t\tthis.#output?.warn(`${message ?? ''}${this.#toLoggableParams(false, params)}`);\n\t}\n\n\terror(ex: Error | unknown, message?: string, ...params: any[]): void;\n\terror(ex: Error | unknown, scope?: ScopedLogger, message?: string, ...params: any[]): void;\n\terror(ex: Error | unknown, scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Error) && !this.isDebugging) return;\n\n\t\tlet message;\n\t\tif (scopeOrMessage == null || typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = `${scopeOrMessage.prefix} ${params.shift() ?? ''}`;\n\t\t}\n\n\t\tif (message == null) {\n\t\t\tconst stack = ex instanceof Error ? ex.stack : undefined;\n\t\t\tif (stack) {\n\t\t\t\tconst match = stackCallerRegex.exec(stack);\n\t\t\t\tif (match != null) {\n\t\t\t\t\tmessage = match[1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tif (ex != null) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[${padOrTruncateEnd(this.#provider!.name, 13)}]`,\n\t\t\t\t\tthis.timestamp,\n\t\t\t\t\tmessage ?? '',\n\t\t\t\t\t...params,\n\t\t\t\t\tex,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[${padOrTruncateEnd(this.#provider!.name, 13)}]`,\n\t\t\t\t\tthis.timestamp,\n\t\t\t\t\tmessage ?? '',\n\t\t\t\t\t...params,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst errorMessage = ` ${message ?? ''}${this.#toLoggableParams(false, params)}`;\n\t\tif (ex != null) {\n\t\t\t// oxlint-disable-next-line typescript/no-base-to-string\n\t\t\tthis.#output?.error(String(ex), errorMessage);\n\t\t} else {\n\t\t\tthis.#output?.error(errorMessage);\n\t\t}\n\t}\n\n\tshowOutputChannel(preserveFocus?: boolean): void {\n\t\tthis.#output?.show?.(preserveFocus);\n\t}\n\n\ttoLoggable(o: any, name?: string): string {\n\t\tif (name != null) {\n\t\t\tconst sanitized = this.sanitize(name, o);\n\t\t\tif (sanitized != null) return sanitized;\n\t\t}\n\n\t\tif (typeof o === 'function') return '<function>';\n\t\tif (o == null || typeof o !== 'object') return String(o);\n\n\t\tif (o instanceof Error) return String(o);\n\n\t\tif (Array.isArray(o)) {\n\t\t\tconst maxItems = 10;\n\t\t\tconst items = o.length > maxItems ? o.slice(0, maxItems) : o;\n\t\t\tconst suffix = o.length > maxItems ? `, …+${o.length - maxItems}` : '';\n\t\t\treturn `[${items.map(i => this.toLoggable(i)).join(', ')}${suffix}]`;\n\t\t}\n\n\t\tconst toLoggable = this.#provider?.toLoggable;\n\n\t\tconst loggable = toLoggable?.(o);\n\t\tif (loggable != null) return loggable;\n\n\t\tconst sanitizeKeys = this.#provider?.sanitizeKeys;\n\n\t\ttry {\n\t\t\treturn JSON.stringify(o, (key: string, value: unknown): unknown => {\n\t\t\t\tif (key.charCodeAt(0) === 95) return undefined; // skip '_'-prefixed keys\n\t\t\t\tif (sanitizeKeys?.has(key)) return this.sanitize(key, value);\n\n\t\t\t\tif (key !== '' && typeof value === 'object' && value != null && !Array.isArray(value)) {\n\t\t\t\t\tif (value instanceof Error) return String(value);\n\t\t\t\t\treturn toLoggable?.(value) ?? value;\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t});\n\t\t} catch {\n\t\t\tdebugger;\n\t\t\treturn '<error>';\n\t\t}\n\t}\n\n\tsanitize(key: string, value: unknown): string | undefined {\n\t\t// Nothing to redact if the value is null/undefined\n\t\tif (value == null) return undefined;\n\n\t\t// Strip leading underscores so `_token` matches `token` in sanitizeKeys\n\t\tconst sanitizeKey = key.replace(leadingUnderscoreRegex, '') || key;\n\t\tif (!this.#provider?.sanitizeKeys?.has(sanitizeKey)) return undefined;\n\n\t\tif (this.#provider.hash != null) {\n\t\t\treturn `<${sanitizeKey}:${this.#provider.hash(typeof value === 'string' ? value : JSON.stringify(value))}>`;\n\t\t}\n\t\treturn `<${sanitizeKey}>`;\n\t}\n\n\t#toLoggableParams(debugOnly: boolean, params: any[]) {\n\t\tif (\n\t\t\tparams.length === 0 ||\n\t\t\t(debugOnly && (this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Debug) && !this.isDebugging)\n\t\t) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst loggableParams = params.map(p => this.toLoggable(p)).join(', ');\n\t\treturn loggableParams.length !== 0 ? ` \\u2014 ${loggableParams}` : '';\n\t}\n}\n\nconst _logger: Logger = new Logger();\nexport { _logger as Logger };\n\nfunction toOrderedLevel(logLevel: LogLevel): OrderedLevel {\n\tswitch (logLevel) {\n\t\tcase 'off':\n\t\t\treturn OrderedLevel.Off;\n\t\tcase 'trace':\n\t\t\treturn OrderedLevel.Trace;\n\t\tcase 'debug':\n\t\t\treturn OrderedLevel.Debug;\n\t\tcase 'info':\n\t\t\treturn OrderedLevel.Info;\n\t\tcase 'warn':\n\t\t\treturn OrderedLevel.Warn;\n\t\tcase 'error':\n\t\t\treturn OrderedLevel.Error;\n\t\tdefault:\n\t\t\treturn OrderedLevel.Off;\n\t}\n}\n\nfunction toFriendlyLogLevel(level: OrderedLevel): LogLevel {\n\tswitch (level) {\n\t\tcase OrderedLevel.Off:\n\t\t\treturn 'off';\n\t\tcase OrderedLevel.Trace:\n\t\t\treturn 'trace';\n\t\tcase OrderedLevel.Debug:\n\t\t\treturn 'debug';\n\t\tcase OrderedLevel.Info:\n\t\t\treturn 'info';\n\t\tcase OrderedLevel.Warn:\n\t\t\treturn 'warn';\n\t\tcase OrderedLevel.Error:\n\t\t\treturn 'error';\n\t\tdefault:\n\t\t\treturn 'off';\n\t}\n}\n\nexport const customLoggableNameFns: WeakMap<object, (instance: any, name: string) => string> = new WeakMap<\n\tobject,\n\t(instance: any, name: string) => string\n>();\n\nexport function getLoggableName(instance: object): string {\n\tlet ctor;\n\tif (typeof instance === 'function') {\n\t\tctor = instance.prototype?.constructor;\n\t\tif (ctor == null) return instance.name;\n\t} else {\n\t\tctor = instance.constructor;\n\t}\n\n\tlet name: string = ctor?.name ?? '';\n\t// Strip webpack module name (since I never name classes with an _)\n\tconst index = name.indexOf('_');\n\tif (index !== -1) {\n\t\tname = name.substring(index + 1);\n\t}\n\n\t// Walk the prototype chain to find a custom name function (supports @logName on base classes)\n\tlet proto = ctor;\n\twhile (proto != null) {\n\t\tconst customNameFn = customLoggableNameFns.get(proto);\n\t\tif (customNameFn != null) {\n\t\t\treturn customNameFn(instance, name);\n\t\t}\n\n\t\tproto = Object.getPrototypeOf(proto);\n\t}\n\n\treturn name;\n}\n\nexport interface LogProvider {\n\tenabled(logLevel: Exclude<LogLevel, 'off'>): boolean;\n\tlog(logLevel: LogLevel, scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n}\n\nexport const defaultLogProvider: LogProvider = {\n\tenabled: (logLevel: Exclude<LogLevel, 'off'>) => _logger.enabled(logLevel),\n\tlog: (logLevel: LogLevel, scope: ScopedLogger | undefined, message: string, ...params: any[]) => {\n\t\tswitch (logLevel) {\n\t\t\tcase 'error':\n\t\t\t\t_logger.error(undefined, scope, message, ...params);\n\t\t\t\tbreak;\n\t\t\tcase 'warn':\n\t\t\t\tscope?.warn(message, ...params);\n\t\t\t\tbreak;\n\t\t\tcase 'info':\n\t\t\t\tscope?.info(message, ...params);\n\t\t\t\tbreak;\n\t\t\tcase 'debug':\n\t\t\t\tscope?.debug(message, ...params);\n\t\t\t\tbreak;\n\t\t\tcase 'trace':\n\t\t\t\tscope?.trace(message, ...params);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tscope?.debug(message, ...params);\n\t\t\t\tbreak;\n\t\t}\n\t},\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logger.js","names":[],"sources":["../../../utils/src/logger.ts"],"sourcesContent":["import { getCurrentScope } from '#env/logScope.js';\nimport type { ScopedLogger } from './logger.scoped.js';\nimport { padOrTruncateEnd } from './string.js';\nimport type { RequireSome } from './types.js';\n\nconst isoTRegex = /T/;\nconst stackCallerRegex = /.*\\s*?at\\s(.+?)\\s/;\nconst leadingUnderscoreRegex = /^_+/;\n\nexport type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport const OrderedLevel = {\n\tOff: 0,\n\tTrace: 1,\n\tDebug: 2,\n\tInfo: 3,\n\tWarn: 4,\n\tError: 5,\n} as const;\nexport type OrderedLevel = (typeof OrderedLevel)[keyof typeof OrderedLevel];\n\nexport interface LogChannelProvider {\n\treadonly name: string;\n\tcreateChannel(name: string): LogChannel;\n\ttoLoggable?(o: unknown): string | undefined;\n\thash?(data: string): string;\n\n\tsanitizeKeys?: Set<string>;\n}\n\nexport interface LogChannel {\n\treadonly name: string;\n\treadonly logLevel: OrderedLevel;\n\treadonly onDidChangeLogLevel?: (listener: (level: OrderedLevel) => void) => { dispose(): void };\n\n\tdispose?(): void;\n\tshow?(preserveFocus?: boolean): void;\n\n\ttrace(message: string, ...args: any[]): void;\n\tdebug(message: string, ...args: any[]): void;\n\tinfo(message: string, ...args: any[]): void;\n\twarn(message: string, ...args: any[]): void;\n\terror(error: string | Error, ...args: any[]): void;\n}\n\nexport interface LoggerOptions {\n\t/**\n\t * Quiets calls decorated with `quiet: true` (reads that mostly hit a cache): no entry line, and an exit line only\n\t * when the call took at least this many milliseconds, failed, or wrote a line while it ran (e.g. ran a git command).\n\t * A quieted call that writes nothing never formats its arguments. Unset, every call logs its entry and exit.\n\t */\n\tquietCallsUnder?: number;\n}\n\nconst defaultSanitizeKeys = ['accessToken', 'password', 'token'];\n\nclass Logger {\n\t#output: LogChannel | undefined;\n\t#provider: RequireSome<LogChannelProvider, 'sanitizeKeys'> | undefined;\n\n\tconfigure(provider: LogChannelProvider, debugging: boolean = false, options?: LoggerOptions): void {\n\t\tthis.#quietCallsUnder = options?.quietCallsUnder;\n\t\tthis.#provider = {\n\t\t\t...provider,\n\t\t\tsanitizeKeys: new Set([...defaultSanitizeKeys, ...(provider.sanitizeKeys ?? [])]),\n\t\t};\n\n\t\tthis.#isDebugging = debugging;\n\n\t\t// Create output channel and sync with the host's log level\n\t\tthis.#output = provider.createChannel(provider.name);\n\t\tthis.#level = this.#output.logLevel;\n\t\tthis.#output.onDidChangeLogLevel?.(level => {\n\t\t\tthis.#level = level;\n\t\t});\n\t}\n\n\tenabled(level?: Exclude<LogLevel, 'off'>): boolean {\n\t\tif (this.isDebugging) return true;\n\t\tif (this.#level === OrderedLevel.Off) return false;\n\t\tif (level == null) return true;\n\n\t\treturn this.#level <= toOrderedLevel(level);\n\t}\n\n\t#quietCallsUnder: number | undefined;\n\tget quietCallsUnder(): number | undefined {\n\t\treturn this.#quietCallsUnder;\n\t}\n\n\t#isDebugging = false;\n\tget isDebugging(): boolean {\n\t\treturn this.#isDebugging;\n\t}\n\n\t#level: OrderedLevel = OrderedLevel.Off;\n\tget logLevel(): LogLevel {\n\t\treturn toFriendlyLogLevel(this.#level);\n\t}\n\n\tget timestamp(): string {\n\t\treturn `[${new Date().toISOString().replace(isoTRegex, ' ').slice(0, -1)}]`;\n\t}\n\n\ttrace(message: string, ...params: any[]): void;\n\ttrace(scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n\ttrace(scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Trace) && !this.isDebugging) return;\n\n\t\tthis.#markScopeLogged(OrderedLevel.Trace, typeof scopeOrMessage === 'string' ? undefined : scopeOrMessage);\n\n\t\tlet message;\n\t\tif (typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = params.shift();\n\n\t\t\tif (scopeOrMessage != null) {\n\t\t\t\tmessage = `${scopeOrMessage.prefix} ${message ?? ''}`;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tconsole.debug(`[${padOrTruncateEnd(this.#provider!.name, 13)}]`, this.timestamp, message ?? '', ...params);\n\t\t}\n\t\tthis.#output?.trace(` ${message ?? ''}${this.#toLoggableParams(true, params)}`);\n\t}\n\n\tdebug(message: string, ...params: any[]): void;\n\tdebug(scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n\tdebug(scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Debug) && !this.isDebugging) return;\n\n\t\tthis.#markScopeLogged(OrderedLevel.Debug, typeof scopeOrMessage === 'string' ? undefined : scopeOrMessage);\n\n\t\tlet message;\n\t\tif (typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = params.shift();\n\n\t\t\tif (scopeOrMessage != null) {\n\t\t\t\tmessage = `${scopeOrMessage.prefix} ${message ?? ''}`;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tconsole.debug(`[${padOrTruncateEnd(this.#provider!.name, 13)}]`, this.timestamp, message ?? '', ...params);\n\t\t}\n\t\tthis.#output?.debug(` ${message ?? ''}${this.#toLoggableParams(false, params)}`);\n\t}\n\n\tinfo(message: string, ...params: any[]): void;\n\tinfo(scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n\tinfo(scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Info) && !this.isDebugging) return;\n\n\t\tthis.#markScopeLogged(OrderedLevel.Info, typeof scopeOrMessage === 'string' ? undefined : scopeOrMessage);\n\n\t\tlet message;\n\t\tif (typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = params.shift();\n\n\t\t\tif (scopeOrMessage != null) {\n\t\t\t\tmessage = `${scopeOrMessage.prefix} ${message ?? ''}`;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tconsole.info(`[${padOrTruncateEnd(this.#provider!.name, 13)}]`, this.timestamp, message ?? '', ...params);\n\t\t}\n\t\tthis.#output?.info(` ${message ?? ''}${this.#toLoggableParams(false, params)}`);\n\t}\n\n\twarn(message: string, ...params: any[]): void;\n\twarn(scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n\twarn(scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Warn) && !this.isDebugging) return;\n\n\t\tthis.#markScopeLogged(OrderedLevel.Warn, typeof scopeOrMessage === 'string' ? undefined : scopeOrMessage);\n\n\t\tlet message;\n\t\tif (typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = params.shift();\n\n\t\t\tif (scopeOrMessage != null) {\n\t\t\t\tmessage = `${scopeOrMessage.prefix} ${message ?? ''}`;\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tconsole.warn(`[${padOrTruncateEnd(this.#provider!.name, 13)}]`, this.timestamp, message ?? '', ...params);\n\t\t}\n\t\tthis.#output?.warn(`${message ?? ''}${this.#toLoggableParams(false, params)}`);\n\t}\n\n\terror(ex: Error | unknown, message?: string, ...params: any[]): void;\n\terror(ex: Error | unknown, scope?: ScopedLogger, message?: string, ...params: any[]): void;\n\terror(ex: Error | unknown, scopeOrMessage: ScopedLogger | string | undefined, ...params: any[]): void {\n\t\tif ((this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Error) && !this.isDebugging) return;\n\n\t\tthis.#markScopeLogged(\n\t\t\tOrderedLevel.Error,\n\t\t\tscopeOrMessage == null || typeof scopeOrMessage === 'string' ? undefined : scopeOrMessage,\n\t\t);\n\n\t\tlet message;\n\t\tif (scopeOrMessage == null || typeof scopeOrMessage === 'string') {\n\t\t\tmessage = scopeOrMessage;\n\t\t} else {\n\t\t\tmessage = `${scopeOrMessage.prefix} ${params.shift() ?? ''}`;\n\t\t}\n\n\t\tif (message == null) {\n\t\t\tconst stack = ex instanceof Error ? ex.stack : undefined;\n\t\t\tif (stack) {\n\t\t\t\tconst match = stackCallerRegex.exec(stack);\n\t\t\t\tif (match != null) {\n\t\t\t\t\tmessage = match[1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.isDebugging) {\n\t\t\tif (ex != null) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[${padOrTruncateEnd(this.#provider!.name, 13)}]`,\n\t\t\t\t\tthis.timestamp,\n\t\t\t\t\tmessage ?? '',\n\t\t\t\t\t...params,\n\t\t\t\t\tex,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[${padOrTruncateEnd(this.#provider!.name, 13)}]`,\n\t\t\t\t\tthis.timestamp,\n\t\t\t\t\tmessage ?? '',\n\t\t\t\t\t...params,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst errorMessage = ` ${message ?? ''}${this.#toLoggableParams(false, params)}`;\n\t\tif (ex != null) {\n\t\t\t// oxlint-disable-next-line typescript/no-base-to-string\n\t\t\tthis.#output?.error(String(ex), errorMessage);\n\t\t} else {\n\t\t\tthis.#output?.error(errorMessage);\n\t\t}\n\t}\n\n\tshowOutputChannel(preserveFocus?: boolean): void {\n\t\tthis.#output?.show?.(preserveFocus);\n\t}\n\n\ttoLoggable(o: any, name?: string): string {\n\t\tif (name != null) {\n\t\t\tconst sanitized = this.sanitize(name, o);\n\t\t\tif (sanitized != null) return sanitized;\n\t\t}\n\n\t\tif (typeof o === 'function') return '<function>';\n\t\tif (o == null || typeof o !== 'object') return String(o);\n\n\t\tif (o instanceof Error) return String(o);\n\n\t\tif (Array.isArray(o)) {\n\t\t\tconst maxItems = 10;\n\t\t\tconst items = o.length > maxItems ? o.slice(0, maxItems) : o;\n\t\t\tconst suffix = o.length > maxItems ? `, …+${o.length - maxItems}` : '';\n\t\t\treturn `[${items.map(i => this.toLoggable(i)).join(', ')}${suffix}]`;\n\t\t}\n\n\t\tconst toLoggable = this.#provider?.toLoggable;\n\n\t\tconst loggable = toLoggable?.(o);\n\t\tif (loggable != null) return loggable;\n\n\t\tconst sanitizeKeys = this.#provider?.sanitizeKeys;\n\n\t\ttry {\n\t\t\treturn JSON.stringify(o, (key: string, value: unknown): unknown => {\n\t\t\t\tif (key.charCodeAt(0) === 95) return undefined; // skip '_'-prefixed keys\n\t\t\t\tif (sanitizeKeys?.has(key)) return this.sanitize(key, value);\n\n\t\t\t\tif (key !== '' && typeof value === 'object' && value != null && !Array.isArray(value)) {\n\t\t\t\t\tif (value instanceof Error) return String(value);\n\t\t\t\t\treturn toLoggable?.(value) ?? value;\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t});\n\t\t} catch {\n\t\t\tdebugger;\n\t\t\treturn '<error>';\n\t\t}\n\t}\n\n\tsanitize(key: string, value: unknown): string | undefined {\n\t\t// Nothing to redact if the value is null/undefined\n\t\tif (value == null) return undefined;\n\n\t\t// Strip leading underscores so `_token` matches `token` in sanitizeKeys\n\t\tconst sanitizeKey = key.replace(leadingUnderscoreRegex, '') || key;\n\t\tif (!this.#provider?.sanitizeKeys?.has(sanitizeKey)) return undefined;\n\n\t\tif (this.#provider.hash != null) {\n\t\t\treturn `<${sanitizeKey}:${this.#provider.hash(typeof value === 'string' ? value : JSON.stringify(value))}>`;\n\t\t}\n\t\treturn `<${sanitizeKey}>`;\n\t}\n\n\t/**\n\t * @internal Records that a line at `level` was written for `scope`'s call, as a line written through the logger\n\t * would; the `@log` decorator uses it for an exit line, which can run outside its call's scope\n\t */\n\tmarkLogged(level: Exclude<LogLevel, 'off'>, scope: ScopedLogger): void {\n\t\tif (!this.#countsAsLogged(toOrderedLevel(level))) return;\n\n\t\tscope.markLogged();\n\t}\n\n\t/** Records that a line was written inside the call (and so every call above it), so a quieted call still logs its exit */\n\t#markScopeLogged(level: OrderedLevel, scope: ScopedLogger | undefined): void {\n\t\tif (!this.#countsAsLogged(level)) return;\n\n\t\t// An explicit scope can be detached (e.g. a Stopwatch's) or belong to an outer call, so the running call is\n\t\t// marked too. The running call goes first: when the explicit scope is one of its callers, marking it first would\n\t\t// write the callers' late entries after the running call's own\n\t\tgetCurrentScope()?.markLogged();\n\t\tscope?.markLogged();\n\t}\n\n\t/** A line only the debugger console shows (`isDebugging` bypasses the channel's level) doesn't count */\n\t#countsAsLogged(level: OrderedLevel): boolean {\n\t\treturn this.#quietCallsUnder != null && this.#level !== OrderedLevel.Off && this.#level <= level;\n\t}\n\n\t#toLoggableParams(debugOnly: boolean, params: any[]) {\n\t\tif (\n\t\t\tparams.length === 0 ||\n\t\t\t(debugOnly && (this.#level === OrderedLevel.Off || this.#level > OrderedLevel.Debug) && !this.isDebugging)\n\t\t) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst loggableParams = params.map(p => this.toLoggable(p)).join(', ');\n\t\treturn loggableParams.length !== 0 ? ` \\u2014 ${loggableParams}` : '';\n\t}\n}\n\nconst _logger: Logger = new Logger();\nexport { _logger as Logger };\n\nfunction toOrderedLevel(logLevel: LogLevel): OrderedLevel {\n\tswitch (logLevel) {\n\t\tcase 'off':\n\t\t\treturn OrderedLevel.Off;\n\t\tcase 'trace':\n\t\t\treturn OrderedLevel.Trace;\n\t\tcase 'debug':\n\t\t\treturn OrderedLevel.Debug;\n\t\tcase 'info':\n\t\t\treturn OrderedLevel.Info;\n\t\tcase 'warn':\n\t\t\treturn OrderedLevel.Warn;\n\t\tcase 'error':\n\t\t\treturn OrderedLevel.Error;\n\t\tdefault:\n\t\t\treturn OrderedLevel.Off;\n\t}\n}\n\nfunction toFriendlyLogLevel(level: OrderedLevel): LogLevel {\n\tswitch (level) {\n\t\tcase OrderedLevel.Off:\n\t\t\treturn 'off';\n\t\tcase OrderedLevel.Trace:\n\t\t\treturn 'trace';\n\t\tcase OrderedLevel.Debug:\n\t\t\treturn 'debug';\n\t\tcase OrderedLevel.Info:\n\t\t\treturn 'info';\n\t\tcase OrderedLevel.Warn:\n\t\t\treturn 'warn';\n\t\tcase OrderedLevel.Error:\n\t\t\treturn 'error';\n\t\tdefault:\n\t\t\treturn 'off';\n\t}\n}\n\nexport const customLoggableNameFns: WeakMap<object, (instance: any, name: string) => string> = new WeakMap<\n\tobject,\n\t(instance: any, name: string) => string\n>();\n\nexport function getLoggableName(instance: object): string {\n\tlet ctor;\n\tif (typeof instance === 'function') {\n\t\tctor = instance.prototype?.constructor;\n\t\tif (ctor == null) return instance.name;\n\t} else {\n\t\tctor = instance.constructor;\n\t}\n\n\tlet name: string = ctor?.name ?? '';\n\t// Strip webpack module name (since I never name classes with an _)\n\tconst index = name.indexOf('_');\n\tif (index !== -1) {\n\t\tname = name.substring(index + 1);\n\t}\n\n\t// Walk the prototype chain to find a custom name function (supports @logName on base classes)\n\tlet proto = ctor;\n\twhile (proto != null) {\n\t\tconst customNameFn = customLoggableNameFns.get(proto);\n\t\tif (customNameFn != null) {\n\t\t\treturn customNameFn(instance, name);\n\t\t}\n\n\t\tproto = Object.getPrototypeOf(proto);\n\t}\n\n\treturn name;\n}\n\nexport interface LogProvider {\n\tenabled(logLevel: Exclude<LogLevel, 'off'>): boolean;\n\tlog(logLevel: LogLevel, scope: ScopedLogger | undefined, message: string, ...params: any[]): void;\n}\n\nexport const defaultLogProvider: LogProvider = {\n\tenabled: (logLevel: Exclude<LogLevel, 'off'>) => _logger.enabled(logLevel),\n\tlog: (logLevel: LogLevel, scope: ScopedLogger | undefined, message: string, ...params: any[]) => {\n\t\tswitch (logLevel) {\n\t\t\tcase 'error':\n\t\t\t\t_logger.error(undefined, scope, message, ...params);\n\t\t\t\tbreak;\n\t\t\tcase 'warn':\n\t\t\t\tscope?.warn(message, ...params);\n\t\t\t\tbreak;\n\t\t\tcase 'info':\n\t\t\t\tscope?.info(message, ...params);\n\t\t\t\tbreak;\n\t\t\tcase 'debug':\n\t\t\t\tscope?.debug(message, ...params);\n\t\t\t\tbreak;\n\t\t\tcase 'trace':\n\t\t\t\tscope?.trace(message, ...params);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tscope?.debug(message, ...params);\n\t\t\t\tbreak;\n\t\t}\n\t},\n};\n"],"mappings":"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"}
|
|
@@ -22,8 +22,19 @@ export interface ScopedLogger {
|
|
|
22
22
|
details: string | undefined;
|
|
23
23
|
failed: string | undefined;
|
|
24
24
|
};
|
|
25
|
+
/** @internal Whether a line was written inside this scope or any scope under it */
|
|
26
|
+
readonly logged: boolean;
|
|
27
|
+
/** @internal Records that a line was written inside this scope, and so inside every scope above it */
|
|
28
|
+
markLogged(): void;
|
|
29
|
+
/** @internal Called when the scope's call returns, so a line written after it no longer triggers `onFirstLogged` */
|
|
30
|
+
exited(): void;
|
|
25
31
|
}
|
|
26
|
-
|
|
32
|
+
/**
|
|
33
|
+
* @param prefix The scope's line prefix, or a function that builds it on first use
|
|
34
|
+
* @param parent The scope this one runs inside, which a line written here also marks as logged
|
|
35
|
+
* @param onFirstLogged Runs when the first line is written inside this scope, after its parent's own `onFirstLogged`
|
|
36
|
+
*/
|
|
37
|
+
export declare function createLogScope(scopeId: number, prevScopeId: number | undefined, prefix: string | (() => string), parent?: ScopedLogger, onFirstLogged?: (scope: ScopedLogger) => void): ScopedLogger;
|
|
27
38
|
export declare function formatLoggableScopeBlock(prefix: string, suffix?: string): string;
|
|
28
39
|
export declare function getLoggableScopeBlock(scopeId: number, prevScopeId?: number, label?: string): string;
|
|
29
40
|
/** Gets the current log scope */
|
|
@@ -4,14 +4,34 @@ import { Logger as _logger } from "./logger.js";
|
|
|
4
4
|
import { enterScope, exitScope, getCurrentScope, runInScope } from "#env/logScope.js";
|
|
5
5
|
//#region ../utils/src/logger.scoped.ts
|
|
6
6
|
const logScopeIdGenerator = getScopedCounter();
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @param prefix The scope's line prefix, or a function that builds it on first use
|
|
9
|
+
* @param parent The scope this one runs inside, which a line written here also marks as logged
|
|
10
|
+
* @param onFirstLogged Runs when the first line is written inside this scope, after its parent's own `onFirstLogged`
|
|
11
|
+
*/
|
|
12
|
+
function createLogScope(scopeId, prevScopeId, prefix, parent, onFirstLogged) {
|
|
8
13
|
let exitDetails;
|
|
9
14
|
let exitFailed;
|
|
15
|
+
let logged = false;
|
|
10
16
|
const scope = {
|
|
11
17
|
scopeId,
|
|
12
18
|
prevScopeId,
|
|
13
19
|
prefix,
|
|
14
20
|
enabled: (level) => _logger.enabled(level),
|
|
21
|
+
get logged() {
|
|
22
|
+
return logged;
|
|
23
|
+
},
|
|
24
|
+
markLogged: function() {
|
|
25
|
+
if (logged) return;
|
|
26
|
+
logged = true;
|
|
27
|
+
parent?.markLogged();
|
|
28
|
+
const fn = onFirstLogged;
|
|
29
|
+
onFirstLogged = void 0;
|
|
30
|
+
fn?.(scope);
|
|
31
|
+
},
|
|
32
|
+
exited: function() {
|
|
33
|
+
onFirstLogged = void 0;
|
|
34
|
+
},
|
|
15
35
|
addExitInfo: function(...details) {
|
|
16
36
|
(exitDetails ??= []).push(...details);
|
|
17
37
|
},
|
|
@@ -25,6 +45,19 @@ function createLogScope(scopeId, prevScopeId, prefix) {
|
|
|
25
45
|
};
|
|
26
46
|
}
|
|
27
47
|
};
|
|
48
|
+
if (typeof prefix === "function") Object.defineProperty(scope, "prefix", {
|
|
49
|
+
configurable: true,
|
|
50
|
+
enumerable: true,
|
|
51
|
+
get: function() {
|
|
52
|
+
const value = prefix();
|
|
53
|
+
Object.defineProperty(scope, "prefix", {
|
|
54
|
+
value,
|
|
55
|
+
writable: false,
|
|
56
|
+
enumerable: true
|
|
57
|
+
});
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
28
61
|
defineLazyBoundMethod(scope, "trace", _logger.trace);
|
|
29
62
|
defineLazyBoundMethod(scope, "debug", _logger.debug);
|
|
30
63
|
defineLazyBoundMethod(scope, "info", _logger.info);
|
|
@@ -82,10 +115,11 @@ function getScopedLogger() {
|
|
|
82
115
|
* @internal only exported for use in other logging-related modules, not for general use
|
|
83
116
|
*/
|
|
84
117
|
function getNewLogScope(prefix, scope, label) {
|
|
85
|
-
if (scope != null && typeof scope !== "boolean") return createLogScope(scope.scopeId, scope.prevScopeId, `${scope.prefix}${prefix}
|
|
86
|
-
const
|
|
118
|
+
if (scope != null && typeof scope !== "boolean") return createLogScope(scope.scopeId, scope.prevScopeId, `${scope.prefix}${prefix}`, scope);
|
|
119
|
+
const parent = scope ? getCurrentScope() : void 0;
|
|
120
|
+
const prevScopeId = parent?.scopeId;
|
|
87
121
|
const scopeId = logScopeIdGenerator.next();
|
|
88
|
-
return createLogScope(scopeId, prevScopeId, `${getLoggableScopeBlock(scopeId, prevScopeId, label)} ${prefix}
|
|
122
|
+
return createLogScope(scopeId, prevScopeId, `${getLoggableScopeBlock(scopeId, prevScopeId, label)} ${prefix}`, parent);
|
|
89
123
|
}
|
|
90
124
|
/** Starts a scoped logger for use with the `using` keyword */
|
|
91
125
|
function startScopedLogger(prefix, scope, label) {
|