@dxos/log 0.8.4-main.b97322e → 0.8.4-main.bbf232bc24
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/dist/lib/browser/chunk-IEP6GGEX.mjs +23 -0
- package/dist/lib/browser/chunk-IEP6GGEX.mjs.map +7 -0
- package/dist/lib/browser/chunk-V7FYKT4H.mjs +311 -0
- package/dist/lib/browser/chunk-V7FYKT4H.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +349 -197
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/platform/browser/index.mjs +26 -0
- package/dist/lib/browser/platform/browser/index.mjs.map +7 -0
- package/dist/lib/browser/platform/node/index.mjs +21 -0
- package/dist/lib/browser/platform/node/index.mjs.map +7 -0
- package/dist/lib/browser/processors/console-processor.mjs +102 -0
- package/dist/lib/browser/processors/console-processor.mjs.map +7 -0
- package/dist/lib/browser/processors/console-stub.mjs +9 -0
- package/dist/lib/browser/processors/console-stub.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs +24 -0
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-5TBDXMQF.mjs +313 -0
- package/dist/lib/node-esm/chunk-5TBDXMQF.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +351 -284
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/platform/browser/index.mjs +27 -0
- package/dist/lib/node-esm/platform/browser/index.mjs.map +7 -0
- package/dist/lib/node-esm/platform/node/index.mjs +22 -0
- package/dist/lib/node-esm/platform/node/index.mjs.map +7 -0
- package/dist/lib/node-esm/processors/console-processor.mjs +103 -0
- package/dist/lib/node-esm/processors/console-processor.mjs.map +7 -0
- package/dist/lib/node-esm/processors/console-stub.mjs +10 -0
- package/dist/lib/node-esm/processors/console-stub.mjs.map +7 -0
- package/dist/types/src/config.d.ts +2 -3
- package/dist/types/src/config.d.ts.map +1 -1
- package/dist/types/src/context.d.ts +78 -2
- package/dist/types/src/context.d.ts.map +1 -1
- package/dist/types/src/dbg.d.ts +23 -0
- package/dist/types/src/dbg.d.ts.map +1 -0
- package/dist/types/src/decorators.d.ts +1 -1
- package/dist/types/src/decorators.d.ts.map +1 -1
- package/dist/types/src/environment.d.ts +24 -0
- package/dist/types/src/environment.d.ts.map +1 -0
- package/dist/types/src/environment.test.d.ts +2 -0
- package/dist/types/src/environment.test.d.ts.map +1 -0
- package/dist/types/src/experimental/ownership.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +7 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/jsonl.d.ts +53 -0
- package/dist/types/src/jsonl.d.ts.map +1 -0
- package/dist/types/src/jsonl.test.d.ts +2 -0
- package/dist/types/src/jsonl.test.d.ts.map +1 -0
- package/dist/types/src/log-buffer.d.ts +20 -0
- package/dist/types/src/log-buffer.d.ts.map +1 -0
- package/dist/types/src/log-buffer.test.d.ts +2 -0
- package/dist/types/src/log-buffer.test.d.ts.map +1 -0
- package/dist/types/src/log.d.ts +55 -18
- package/dist/types/src/log.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +20 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/options.d.ts +1 -6
- package/dist/types/src/options.d.ts.map +1 -1
- package/dist/types/src/platform/browser/index.d.ts.map +1 -1
- package/dist/types/src/platform/index.d.ts +1 -1
- package/dist/types/src/platform/index.d.ts.map +1 -1
- package/dist/types/src/platform/node/index.d.ts.map +1 -1
- package/dist/types/src/processors/browser-processor.d.ts.map +1 -1
- package/dist/types/src/processors/common.d.ts.map +1 -1
- package/dist/types/src/processors/console-processor.d.ts.map +1 -1
- package/dist/types/src/processors/file-processor.d.ts.map +1 -1
- package/dist/types/src/processors/index.d.ts +3 -3
- package/dist/types/src/processors/index.d.ts.map +1 -1
- package/dist/types/src/scope.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -17
- package/src/config.ts +3 -2
- package/src/context.ts +278 -7
- package/src/dbg.ts +34 -0
- package/src/decorators.ts +3 -3
- package/src/environment.test.ts +222 -0
- package/src/environment.ts +129 -0
- package/src/experimental/classes.test.ts +1 -1
- package/src/index.ts +7 -4
- package/src/jsonl.test.ts +121 -0
- package/src/jsonl.ts +104 -0
- package/src/log-buffer.test.ts +158 -0
- package/src/log-buffer.ts +89 -0
- package/src/log.test.ts +48 -18
- package/src/log.ts +146 -58
- package/src/meta.ts +29 -1
- package/src/options.ts +27 -11
- package/src/platform/index.ts +1 -1
- package/src/processors/browser-processor.ts +29 -28
- package/src/processors/console-processor.ts +9 -13
- package/src/processors/file-processor.ts +9 -8
- package/src/processors/index.ts +3 -3
- package/src/scope.ts +1 -1
package/package.json
CHANGED
|
@@ -1,47 +1,62 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/log",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.bbf232bc24",
|
|
4
4
|
"description": "Logger",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "DXOS.org",
|
|
9
13
|
"sideEffects": true,
|
|
10
14
|
"type": "module",
|
|
15
|
+
"imports": {
|
|
16
|
+
"#platform": {
|
|
17
|
+
"source": {
|
|
18
|
+
"browser": "./src/platform/browser/index.ts",
|
|
19
|
+
"default": "./src/platform/node/index.ts"
|
|
20
|
+
},
|
|
21
|
+
"types": "./dist/types/src/platform/node/index.d.ts",
|
|
22
|
+
"browser": "./dist/lib/browser/platform/browser/index.mjs",
|
|
23
|
+
"default": "./dist/lib/node-esm/platform/node/index.mjs"
|
|
24
|
+
},
|
|
25
|
+
"#console-processor": {
|
|
26
|
+
"source": {
|
|
27
|
+
"browser": "./src/processors/console-stub.ts",
|
|
28
|
+
"default": "./src/processors/console-processor.ts"
|
|
29
|
+
},
|
|
30
|
+
"types": "./dist/types/src/processors/console-processor.d.ts",
|
|
31
|
+
"browser": "./dist/lib/browser/processors/console-stub.mjs",
|
|
32
|
+
"default": "./dist/lib/node-esm/processors/console-processor.mjs"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
11
35
|
"exports": {
|
|
12
36
|
".": {
|
|
37
|
+
"types": "./dist/types/src/index.d.ts",
|
|
13
38
|
"browser": "./dist/lib/browser/index.mjs",
|
|
14
39
|
"node": {
|
|
15
40
|
"require": "./dist/lib/node/index.cjs",
|
|
16
41
|
"default": "./dist/lib/node-esm/index.mjs"
|
|
17
|
-
}
|
|
18
|
-
"types": "./dist/types/src/index.d.ts"
|
|
42
|
+
}
|
|
19
43
|
}
|
|
20
44
|
},
|
|
21
|
-
"browser": {
|
|
22
|
-
"./src/platform/node/index.ts": "./src/platform/browser/index.ts",
|
|
23
|
-
"./src/processors/console-processor.ts": "./src/processors/console-stub.ts"
|
|
24
|
-
},
|
|
25
45
|
"types": "dist/types/src/index.d.ts",
|
|
26
|
-
"typesVersions": {
|
|
27
|
-
"*": {}
|
|
28
|
-
},
|
|
29
46
|
"files": [
|
|
30
47
|
"dist",
|
|
31
48
|
"src"
|
|
32
49
|
],
|
|
33
50
|
"dependencies": {
|
|
34
|
-
"chalk": "^4.1.
|
|
35
|
-
"js-yaml": "
|
|
51
|
+
"chalk": "^4.1.2",
|
|
52
|
+
"js-yaml": "4.1.1",
|
|
36
53
|
"lodash.defaultsdeep": "^4.6.1",
|
|
37
|
-
"
|
|
38
|
-
"@dxos/node-std": "0.8.4-main.
|
|
39
|
-
"@dxos/util": "0.8.4-main.b97322e"
|
|
54
|
+
"@dxos/util": "0.8.4-main.bbf232bc24",
|
|
55
|
+
"@dxos/node-std": "0.8.4-main.bbf232bc24"
|
|
40
56
|
},
|
|
41
57
|
"devDependencies": {
|
|
42
58
|
"@types/js-yaml": "^4.0.5",
|
|
43
|
-
"@types/lodash.defaultsdeep": "^4.6.6"
|
|
44
|
-
"@types/lodash.omit": "^4.5.7"
|
|
59
|
+
"@types/lodash.defaultsdeep": "^4.6.6"
|
|
45
60
|
},
|
|
46
61
|
"publishConfig": {
|
|
47
62
|
"access": "public"
|
package/src/config.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { type LogProcessor } from './context';
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Standard levels.
|
|
9
|
+
* NOTE: Keep aligned with LogLevel in @dxos/protocols.
|
|
9
10
|
*/
|
|
10
|
-
// NOTE: Keep aligned with LogLevel in @dxos/protocols.
|
|
11
11
|
// TODO(burdon): Update numbers?
|
|
12
12
|
export enum LogLevel {
|
|
13
13
|
TRACE = 5,
|
|
@@ -18,7 +18,8 @@ export enum LogLevel {
|
|
|
18
18
|
ERROR = 14,
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export const levels:
|
|
21
|
+
export const levels: Record<string, LogLevel> = {
|
|
22
|
+
'*': LogLevel.TRACE,
|
|
22
23
|
trace: LogLevel.TRACE,
|
|
23
24
|
debug: LogLevel.DEBUG,
|
|
24
25
|
verbose: LogLevel.VERBOSE,
|
package/src/context.ts
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { getDebugName } from '@dxos/util';
|
|
6
|
+
|
|
5
7
|
import { type LogConfig, type LogFilter, type LogLevel } from './config';
|
|
6
8
|
import { type CallMetadata } from './meta';
|
|
9
|
+
import { getRelativeFilename } from './processors/common';
|
|
7
10
|
import { gatherLogInfoFromScope } from './scope';
|
|
8
11
|
|
|
9
12
|
/**
|
|
@@ -12,14 +15,140 @@ import { gatherLogInfoFromScope } from './scope';
|
|
|
12
15
|
export type LogContext = Record<string, any> | Error | any;
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
|
-
*
|
|
18
|
+
* Normalized call-site metadata suitable for display and serialization.
|
|
16
19
|
*/
|
|
17
|
-
export interface
|
|
20
|
+
export interface ComputedLogMeta {
|
|
21
|
+
/** Relative filename (normalized via {@link getRelativeFilename}). */
|
|
22
|
+
filename?: string;
|
|
23
|
+
|
|
24
|
+
/** Line number within the file. */
|
|
25
|
+
line?: number;
|
|
26
|
+
|
|
27
|
+
/** Debug name of the enclosing scope (class instance), e.g. `MyClass#3`. */
|
|
28
|
+
context?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Fields required to construct a {@link LogEntry}.
|
|
33
|
+
*/
|
|
34
|
+
export interface LogEntryInit {
|
|
18
35
|
level: LogLevel;
|
|
19
36
|
message?: string;
|
|
20
37
|
context?: LogContext;
|
|
21
38
|
meta?: CallMetadata;
|
|
22
39
|
error?: Error;
|
|
40
|
+
/** Overrides the default timestamp ({@link Date.now}). */
|
|
41
|
+
timestamp?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Record for a single log line processed by the logging pipeline.
|
|
46
|
+
*
|
|
47
|
+
* Raw fields (`level`, `message`, `context`, `meta`, `error`) are preserved so processors
|
|
48
|
+
* can access unmodified inputs. Derived, lazily computed getters
|
|
49
|
+
* ({@link computedContext}, {@link computedError}, {@link computedMeta}) centralize
|
|
50
|
+
* the formatting logic shared across processors that write to serialized stores.
|
|
51
|
+
*/
|
|
52
|
+
export class LogEntry {
|
|
53
|
+
/** Severity of this entry. */
|
|
54
|
+
readonly level: LogLevel;
|
|
55
|
+
|
|
56
|
+
/** Human-readable log message, if any. */
|
|
57
|
+
readonly message?: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Raw context value passed at the call site. May be a record, an Error, a function
|
|
61
|
+
* returning either, or any other value. Processors that need the flattened /
|
|
62
|
+
* JSON-safe view should prefer {@link computedContext}.
|
|
63
|
+
*/
|
|
64
|
+
readonly context?: LogContext;
|
|
65
|
+
|
|
66
|
+
/** Raw call-site metadata injected by the log transform plugin. */
|
|
67
|
+
readonly meta?: CallMetadata;
|
|
68
|
+
|
|
69
|
+
/** Error passed to `log.catch()` / `log.error(err)`, if any. */
|
|
70
|
+
readonly error?: Error;
|
|
71
|
+
|
|
72
|
+
/** Unix timestamp in milliseconds of when the entry was created. */
|
|
73
|
+
readonly timestamp: number;
|
|
74
|
+
|
|
75
|
+
#computedContext: Record<string, unknown> | undefined;
|
|
76
|
+
#computedContextComputed = false;
|
|
77
|
+
#computedError: string | undefined;
|
|
78
|
+
#computedErrorComputed = false;
|
|
79
|
+
#computedMeta: ComputedLogMeta | undefined;
|
|
80
|
+
#resolvedContext: unknown;
|
|
81
|
+
#resolvedContextComputed = false;
|
|
82
|
+
|
|
83
|
+
constructor(init: LogEntryInit) {
|
|
84
|
+
this.level = init.level;
|
|
85
|
+
this.message = init.message;
|
|
86
|
+
this.context = init.context;
|
|
87
|
+
this.meta = init.meta;
|
|
88
|
+
this.error = init.error;
|
|
89
|
+
this.timestamp = init.timestamp ?? Date.now();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Resolve a function-valued {@link context} once and cache, so getters that
|
|
94
|
+
* independently consult the raw context don't trigger duplicate evaluation.
|
|
95
|
+
*/
|
|
96
|
+
#resolveContext(): unknown {
|
|
97
|
+
if (!this.#resolvedContextComputed) {
|
|
98
|
+
this.#resolvedContext = typeof this.context === 'function' ? this.context() : this.context;
|
|
99
|
+
this.#resolvedContextComputed = true;
|
|
100
|
+
}
|
|
101
|
+
return this.#resolvedContext;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Flattened, JSON-safe context intended for serialized stores.
|
|
106
|
+
*
|
|
107
|
+
* - Single-level key-value map.
|
|
108
|
+
* - Primitives (`boolean`, `number`, `string`, `null`, `undefined`) pass through.
|
|
109
|
+
* - Non-primitive values are stringified one level deep via `JSON.stringify` (no recursion).
|
|
110
|
+
* - The reserved `error` / `err` keys are stripped — use {@link computedError} instead.
|
|
111
|
+
* - Properties from `@logInfo`-decorated members of the scope (`meta.S`) are inlined.
|
|
112
|
+
*
|
|
113
|
+
* Lazily computed and memoized on first access.
|
|
114
|
+
*/
|
|
115
|
+
get computedContext(): Record<string, unknown> {
|
|
116
|
+
if (!this.#computedContextComputed) {
|
|
117
|
+
this.#computedContext = computeContext(this, this.#resolveContext());
|
|
118
|
+
this.#computedContextComputed = true;
|
|
119
|
+
}
|
|
120
|
+
return this.#computedContext ?? {};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Stringified error for this entry, sourced (in priority order) from:
|
|
125
|
+
* 1. {@link error} (e.g. `log.catch(err)`),
|
|
126
|
+
* 2. {@link context} when the context itself is an {@link Error},
|
|
127
|
+
* 3. `context.error` or `context.err`.
|
|
128
|
+
*
|
|
129
|
+
* Formatted as `.stack` when available, falling back to `.message` or `String(err)`.
|
|
130
|
+
*
|
|
131
|
+
* Lazily computed and memoized on first access.
|
|
132
|
+
*/
|
|
133
|
+
get computedError(): string | undefined {
|
|
134
|
+
if (!this.#computedErrorComputed) {
|
|
135
|
+
this.#computedError = computeError(this, this.#resolveContext());
|
|
136
|
+
this.#computedErrorComputed = true;
|
|
137
|
+
}
|
|
138
|
+
return this.#computedError;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Normalized call-site metadata suitable for display / serialization.
|
|
143
|
+
*
|
|
144
|
+
* Lazily computed and memoized on first access.
|
|
145
|
+
*/
|
|
146
|
+
get computedMeta(): ComputedLogMeta {
|
|
147
|
+
if (this.#computedMeta === undefined) {
|
|
148
|
+
this.#computedMeta = computeMeta(this);
|
|
149
|
+
}
|
|
150
|
+
return this.#computedMeta;
|
|
151
|
+
}
|
|
23
152
|
}
|
|
24
153
|
|
|
25
154
|
/**
|
|
@@ -27,8 +156,33 @@ export interface LogEntry {
|
|
|
27
156
|
*/
|
|
28
157
|
export type LogProcessor = (config: LogConfig, entry: LogEntry) => void;
|
|
29
158
|
|
|
30
|
-
|
|
31
|
-
|
|
159
|
+
/**
|
|
160
|
+
* Returns:
|
|
161
|
+
* true if the log entry matches the filter,
|
|
162
|
+
* false if should be excluded, or
|
|
163
|
+
* undefined if it the filter doesn't match the level.
|
|
164
|
+
*/
|
|
165
|
+
const matchFilter = (filter: LogFilter, level: LogLevel, path?: string): boolean | undefined => {
|
|
166
|
+
// TODO(burdon): Support regexp.
|
|
167
|
+
if (filter.pattern?.startsWith('-')) {
|
|
168
|
+
// Exclude.
|
|
169
|
+
if (path?.includes(filter.pattern.slice(1))) {
|
|
170
|
+
if (level >= filter.level) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
// Include.
|
|
176
|
+
if (filter.pattern?.length) {
|
|
177
|
+
if (path?.includes(filter.pattern)) {
|
|
178
|
+
return level >= filter.level;
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
if (level >= filter.level) {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
32
186
|
};
|
|
33
187
|
|
|
34
188
|
/**
|
|
@@ -36,12 +190,24 @@ const matchFilter = (filter: LogFilter, level: LogLevel, path: string) => {
|
|
|
36
190
|
*/
|
|
37
191
|
export const shouldLog = (entry: LogEntry, filters?: LogFilter[]): boolean => {
|
|
38
192
|
if (filters === undefined) {
|
|
39
|
-
return
|
|
40
|
-
} else {
|
|
41
|
-
return filters.some((filter) => matchFilter(filter, entry.level, entry.meta?.F ?? ''));
|
|
193
|
+
return false;
|
|
42
194
|
}
|
|
195
|
+
|
|
196
|
+
const results = filters
|
|
197
|
+
.map((filter) => matchFilter(filter, entry.level, entry.meta?.F))
|
|
198
|
+
.filter((result): result is boolean => result !== undefined);
|
|
199
|
+
|
|
200
|
+
// Skip if any are explicitely false.
|
|
201
|
+
// console.log({ level: entry.level, path: entry.meta?.F }, filters, results, results.length);
|
|
202
|
+
return results.length > 0 && !results.some((results) => results === false);
|
|
43
203
|
};
|
|
44
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Merges scope info, entry context, and error into a single record — preserving nested
|
|
207
|
+
* objects and Error instances so rich consumers (console inspect, devtools) can format them.
|
|
208
|
+
*
|
|
209
|
+
* Prefer {@link LogEntry.computedContext} for serialized / JSON outputs.
|
|
210
|
+
*/
|
|
45
211
|
export const getContextFromEntry = (entry: LogEntry): Record<string, any> | undefined => {
|
|
46
212
|
let context;
|
|
47
213
|
if (entry.meta) {
|
|
@@ -69,3 +235,108 @@ export const getContextFromEntry = (entry: LogEntry): Record<string, any> | unde
|
|
|
69
235
|
|
|
70
236
|
return context && Object.keys(context).length > 0 ? context : undefined;
|
|
71
237
|
};
|
|
238
|
+
|
|
239
|
+
const RESERVED_ERROR_KEYS = new Set(['error', 'err']);
|
|
240
|
+
|
|
241
|
+
const stringifyOneLevel = (value: unknown): unknown => {
|
|
242
|
+
if (value === null || value === undefined) {
|
|
243
|
+
return value;
|
|
244
|
+
}
|
|
245
|
+
const type = typeof value;
|
|
246
|
+
if (type === 'boolean' || type === 'number' || type === 'string') {
|
|
247
|
+
return value;
|
|
248
|
+
}
|
|
249
|
+
if (type === 'bigint') {
|
|
250
|
+
return (value as bigint).toString();
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
return JSON.stringify(value);
|
|
254
|
+
} catch {
|
|
255
|
+
return String(value);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const computeContext = (entry: LogEntry, rawContext: unknown): Record<string, unknown> => {
|
|
260
|
+
const result: Record<string, unknown> = {};
|
|
261
|
+
|
|
262
|
+
const mergeInto = (source: unknown): void => {
|
|
263
|
+
if (!source || typeof source !== 'object') {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
for (const [key, value] of Object.entries(source)) {
|
|
267
|
+
if (RESERVED_ERROR_KEYS.has(key)) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
result[key] = stringifyOneLevel(value);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
if (entry.meta?.S !== undefined && entry.meta.S !== null) {
|
|
275
|
+
mergeInto(gatherLogInfoFromScope(entry.meta.S));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (rawContext instanceof Error) {
|
|
279
|
+
// Structured debug info attached to thrown errors lives on `.context`.
|
|
280
|
+
mergeInto((rawContext as any).context);
|
|
281
|
+
} else {
|
|
282
|
+
mergeInto(rawContext);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (entry.error) {
|
|
286
|
+
mergeInto((entry.error as any).context);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return result;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const stringifyError = (err: unknown): string | undefined => {
|
|
293
|
+
if (err === null || err === undefined) {
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
if (err instanceof Error) {
|
|
297
|
+
return err.stack ?? err.message;
|
|
298
|
+
}
|
|
299
|
+
return String(err);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const computeError = (entry: LogEntry, rawContext: unknown): string | undefined => {
|
|
303
|
+
if (entry.error !== undefined) {
|
|
304
|
+
return stringifyError(entry.error);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (rawContext instanceof Error) {
|
|
308
|
+
return stringifyError(rawContext);
|
|
309
|
+
}
|
|
310
|
+
if (rawContext && typeof rawContext === 'object') {
|
|
311
|
+
const ctxErr = (rawContext as any).error ?? (rawContext as any).err;
|
|
312
|
+
if (ctxErr !== undefined && ctxErr !== null) {
|
|
313
|
+
return stringifyError(ctxErr);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return undefined;
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const computeMeta = (entry: LogEntry): ComputedLogMeta => {
|
|
321
|
+
if (!entry.meta) {
|
|
322
|
+
return {};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const scope = entry.meta.S;
|
|
326
|
+
// Skip globalThis and plain object scopes (module-level logs); only report class instances.
|
|
327
|
+
let scopeContext: string | undefined;
|
|
328
|
+
if (
|
|
329
|
+
typeof scope === 'object' &&
|
|
330
|
+
scope !== null &&
|
|
331
|
+
scope !== globalThis &&
|
|
332
|
+
Object.getPrototypeOf(scope) !== Object.prototype
|
|
333
|
+
) {
|
|
334
|
+
scopeContext = getDebugName(scope);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
filename: getRelativeFilename(entry.meta.F),
|
|
339
|
+
line: entry.meta.L,
|
|
340
|
+
context: scopeContext,
|
|
341
|
+
};
|
|
342
|
+
};
|
package/src/dbg.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type CallMetadata } from './meta';
|
|
6
|
+
/**
|
|
7
|
+
* Debug-log value to console.
|
|
8
|
+
* Log's the expression being evaluated.
|
|
9
|
+
*
|
|
10
|
+
* If only one argument is provided, it will also be returned.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* dbg(foo, bar);
|
|
15
|
+
* // foo = 1
|
|
16
|
+
* // bar = 2
|
|
17
|
+
*
|
|
18
|
+
* bar = dbg(foo * 2);
|
|
19
|
+
* // foo * 2 = 2
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* NOTE: The second argument is injected by the log transform plugin.
|
|
23
|
+
*/
|
|
24
|
+
export const dbg: {
|
|
25
|
+
<T>(value: T, _meta?: CallMetadata): T;
|
|
26
|
+
} = <T>(arg: T, meta?: CallMetadata): T => {
|
|
27
|
+
if (meta?.A) {
|
|
28
|
+
console.log(`${meta.A[0]} =`, arg);
|
|
29
|
+
} else {
|
|
30
|
+
console.log(arg);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return arg;
|
|
34
|
+
};
|
package/src/decorators.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import { inspect } from 'node:util';
|
|
7
7
|
|
|
8
|
-
import type
|
|
8
|
+
import { type LogMethods } from './log';
|
|
9
9
|
import { type CallMetadata } from './meta';
|
|
10
10
|
|
|
11
11
|
let nextPromiseId = 0;
|
|
@@ -190,13 +190,13 @@ const logAsyncRejected = (
|
|
|
190
190
|
);
|
|
191
191
|
};
|
|
192
192
|
|
|
193
|
+
const COLOR_FUNCTION = [220, 220, 170] as const;
|
|
194
|
+
|
|
193
195
|
// https://github.com/dxos/dxos/issues/7286
|
|
194
196
|
const greenCheck = typeof chalk.green === 'function' ? chalk.green('✔') : '✔';
|
|
195
197
|
|
|
196
198
|
const formatTimeElapsed = (startTime: number) => chalk.gray(`${(performance.now() - startTime).toFixed(0)}ms`);
|
|
197
199
|
|
|
198
|
-
const COLOR_FUNCTION = [220, 220, 170] as const;
|
|
199
|
-
|
|
200
200
|
const formatFunction = (name: string) => chalk.bold(chalk.rgb(...COLOR_FUNCTION)(name));
|
|
201
201
|
|
|
202
202
|
const formatPromise = (id: number) => chalk.blue(`Promise#${id}`);
|