@dxos/log 0.8.4-main.67995b8 → 0.8.4-main.69d29f4
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-GPOFUMLO.mjs +133 -0
- package/dist/lib/browser/chunk-GPOFUMLO.mjs.map +7 -0
- package/dist/lib/browser/chunk-IEP6GGEX.mjs +23 -0
- package/dist/lib/browser/chunk-IEP6GGEX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +136 -177
- 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 +107 -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-QPYJZ4SO.mjs +135 -0
- package/dist/lib/node-esm/chunk-QPYJZ4SO.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +133 -259
- 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 +108 -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.map +1 -1
- package/dist/types/src/decorators.d.ts +1 -1
- package/dist/types/src/decorators.d.ts.map +1 -1
- package/dist/types/src/log.d.ts +12 -18
- package/dist/types/src/log.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/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/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/tsconfig.tsbuildinfo +1 -1
- package/package.json +31 -11
- package/src/config.ts +3 -2
- package/src/context.ts +36 -5
- package/src/decorators.ts +5 -4
- package/src/experimental/classes.test.ts +2 -1
- package/src/log.test.ts +49 -18
- package/src/log.ts +101 -57
- package/src/options.ts +27 -11
- package/src/platform/index.ts +1 -1
- package/src/platform/node/index.ts +2 -1
- package/src/processors/browser-processor.ts +3 -1
- package/src/processors/console-processor.ts +9 -5
- package/src/processors/file-processor.ts +4 -1
- package/src/processors/index.ts +3 -3
- package/src/scope.ts +1 -1
package/package.json
CHANGED
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/log",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.69d29f4",
|
|
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
46
|
"typesVersions": {
|
|
27
47
|
"*": {}
|
|
@@ -31,12 +51,12 @@
|
|
|
31
51
|
"src"
|
|
32
52
|
],
|
|
33
53
|
"dependencies": {
|
|
34
|
-
"chalk": "^4.1.
|
|
35
|
-
"js-yaml": "
|
|
54
|
+
"chalk": "^4.1.2",
|
|
55
|
+
"js-yaml": "4.1.1",
|
|
36
56
|
"lodash.defaultsdeep": "^4.6.1",
|
|
37
57
|
"lodash.omit": "^4.5.0",
|
|
38
|
-
"@dxos/node-std": "0.8.4-main.
|
|
39
|
-
"@dxos/util": "0.8.4-main.
|
|
58
|
+
"@dxos/node-std": "0.8.4-main.69d29f4",
|
|
59
|
+
"@dxos/util": "0.8.4-main.69d29f4"
|
|
40
60
|
},
|
|
41
61
|
"devDependencies": {
|
|
42
62
|
"@types/js-yaml": "^4.0.5",
|
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
|
@@ -27,8 +27,33 @@ export interface LogEntry {
|
|
|
27
27
|
*/
|
|
28
28
|
export type LogProcessor = (config: LogConfig, entry: LogEntry) => void;
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Returns:
|
|
32
|
+
* true if the log entry matches the filter,
|
|
33
|
+
* false if should be excluded, or
|
|
34
|
+
* undefined if it the filter doesn't match the level.
|
|
35
|
+
*/
|
|
36
|
+
const matchFilter = (filter: LogFilter, level: LogLevel, path?: string): boolean | undefined => {
|
|
37
|
+
// TODO(burdon): Support regexp.
|
|
38
|
+
if (filter.pattern?.startsWith('-')) {
|
|
39
|
+
// Exclude.
|
|
40
|
+
if (path?.includes(filter.pattern.slice(1))) {
|
|
41
|
+
if (level >= filter.level) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// Include.
|
|
47
|
+
if (filter.pattern?.length) {
|
|
48
|
+
if (path?.includes(filter.pattern)) {
|
|
49
|
+
return level >= filter.level;
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
if (level >= filter.level) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
32
57
|
};
|
|
33
58
|
|
|
34
59
|
/**
|
|
@@ -36,10 +61,16 @@ const matchFilter = (filter: LogFilter, level: LogLevel, path: string) => {
|
|
|
36
61
|
*/
|
|
37
62
|
export const shouldLog = (entry: LogEntry, filters?: LogFilter[]): boolean => {
|
|
38
63
|
if (filters === undefined) {
|
|
39
|
-
return
|
|
40
|
-
} else {
|
|
41
|
-
return filters.some((filter) => matchFilter(filter, entry.level, entry.meta?.F ?? ''));
|
|
64
|
+
return false;
|
|
42
65
|
}
|
|
66
|
+
|
|
67
|
+
const results = filters
|
|
68
|
+
.map((filter) => matchFilter(filter, entry.level, entry.meta?.F))
|
|
69
|
+
.filter((result): result is boolean => result !== undefined);
|
|
70
|
+
|
|
71
|
+
// Skip if any are explicitely false.
|
|
72
|
+
// console.log({ level: entry.level, path: entry.meta?.F }, filters, results, results.length);
|
|
73
|
+
return results.length > 0 && !results.some((results) => results === false);
|
|
43
74
|
};
|
|
44
75
|
|
|
45
76
|
export const getContextFromEntry = (entry: LogEntry): Record<string, any> | undefined => {
|
package/src/decorators.ts
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import chalk from 'chalk';
|
|
6
5
|
import { inspect } from 'node:util';
|
|
7
6
|
|
|
8
|
-
import
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
import { type LogMethods } from './log';
|
|
9
10
|
import { type CallMetadata } from './meta';
|
|
10
11
|
|
|
11
12
|
let nextPromiseId = 0;
|
|
@@ -190,13 +191,13 @@ const logAsyncRejected = (
|
|
|
190
191
|
);
|
|
191
192
|
};
|
|
192
193
|
|
|
194
|
+
const COLOR_FUNCTION = [220, 220, 170] as const;
|
|
195
|
+
|
|
193
196
|
// https://github.com/dxos/dxos/issues/7286
|
|
194
197
|
const greenCheck = typeof chalk.green === 'function' ? chalk.green('✔') : '✔';
|
|
195
198
|
|
|
196
199
|
const formatTimeElapsed = (startTime: number) => chalk.gray(`${(performance.now() - startTime).toFixed(0)}ms`);
|
|
197
200
|
|
|
198
|
-
const COLOR_FUNCTION = [220, 220, 170] as const;
|
|
199
|
-
|
|
200
201
|
const formatFunction = (name: string) => chalk.bold(chalk.rgb(...COLOR_FUNCTION)(name));
|
|
201
202
|
|
|
202
203
|
const formatPromise = (id: number) => chalk.blue(`Promise#${id}`);
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import { describe, test } from 'vitest';
|
|
6
6
|
|
|
7
|
-
import { debugInfo, ownershipClass } from './ownership';
|
|
8
7
|
import { log } from '../log';
|
|
9
8
|
|
|
9
|
+
import { debugInfo, ownershipClass } from './ownership';
|
|
10
|
+
|
|
10
11
|
describe('classes', function () {
|
|
11
12
|
test('field instance', function () {
|
|
12
13
|
@ownershipClass
|
package/src/log.test.ts
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
import { beforeEach, describe, test } from 'vitest';
|
|
7
8
|
|
|
8
9
|
import { LogLevel } from './config';
|
|
9
|
-
import {
|
|
10
|
+
import { shouldLog } from './context';
|
|
11
|
+
import { type Log, createLog } from './log';
|
|
10
12
|
|
|
11
13
|
class LogError extends Error {
|
|
12
14
|
constructor(
|
|
@@ -24,13 +26,52 @@ class LogError extends Error {
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
log
|
|
28
|
-
|
|
29
|
-
});
|
|
29
|
+
describe('log', () => {
|
|
30
|
+
let log!: Log;
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
log = createLog();
|
|
34
|
+
log.config({
|
|
35
|
+
filter: LogLevel.DEBUG,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('filters', ({ expect }) => {
|
|
40
|
+
const tests = [
|
|
41
|
+
{ expected: 0, filter: 'ERROR' },
|
|
42
|
+
{ expected: 2, filter: 'INFO' },
|
|
43
|
+
{ expected: 1, filter: 'foo:INFO' },
|
|
44
|
+
{ expected: 4, filter: 'DEBUG' },
|
|
45
|
+
{ expected: 2, filter: 'DEBUG,-foo:*' },
|
|
46
|
+
{ expected: 1, filter: 'INFO,-foo:*' },
|
|
47
|
+
{ expected: 3, filter: 'DEBUG,-foo:INFO' },
|
|
48
|
+
{ expected: 3, filter: 'foo:DEBUG,bar:INFO' },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
for (const test of tests) {
|
|
52
|
+
let count = 0;
|
|
53
|
+
const log = createLog();
|
|
54
|
+
const remove = log.addProcessor((config, entry) => {
|
|
55
|
+
if (shouldLog(entry, config.filters)) {
|
|
56
|
+
count++;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
log.config({
|
|
60
|
+
filter: test.filter,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.group(`Filter: "${test.filter}"`);
|
|
64
|
+
log.debug('line 1', {}, { F: 'foo.ts', L: 1, S: undefined });
|
|
65
|
+
log.info('line 2', {}, { F: 'foo.ts', L: 2, S: undefined });
|
|
66
|
+
log.debug('line 3', {}, { F: 'bar.ts', L: 3, S: undefined });
|
|
67
|
+
log.info('line 4', {}, { F: 'bar.ts', L: 4, S: undefined });
|
|
68
|
+
console.groupEnd();
|
|
69
|
+
|
|
70
|
+
expect(count, `Filter: "${test.filter}"`).toBe(test.expected);
|
|
71
|
+
remove();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
32
74
|
|
|
33
|
-
describe('log', () => {
|
|
34
75
|
test('throws an error', () => {
|
|
35
76
|
try {
|
|
36
77
|
throw new LogError('Test failed', { value: 1 });
|
|
@@ -55,16 +96,6 @@ describe('log', () => {
|
|
|
55
96
|
}
|
|
56
97
|
});
|
|
57
98
|
|
|
58
|
-
test('config', () => {
|
|
59
|
-
log.config({
|
|
60
|
-
filter: LogLevel.INFO,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
log.debug('Debug level log message');
|
|
64
|
-
log.info('Info level log message');
|
|
65
|
-
log.warn('Warn level log message');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
99
|
test('config file', () => {
|
|
69
100
|
log.config({
|
|
70
101
|
file: path.join('packages/common/log/test-config.yml'),
|
|
@@ -90,7 +121,7 @@ describe('log', () => {
|
|
|
90
121
|
});
|
|
91
122
|
});
|
|
92
123
|
|
|
93
|
-
test('error',
|
|
124
|
+
test('error', () => {
|
|
94
125
|
const myError = new Error('Test error', { cause: new Error('Cause') });
|
|
95
126
|
log.catch(myError);
|
|
96
127
|
});
|
package/src/log.ts
CHANGED
|
@@ -6,7 +6,14 @@ import { type LogConfig, LogLevel, type LogOptions } from './config';
|
|
|
6
6
|
import { type LogContext, type LogProcessor } from './context';
|
|
7
7
|
import { createFunctionLogDecorator, createMethodLogDecorator } from './decorators';
|
|
8
8
|
import { type CallMetadata } from './meta';
|
|
9
|
-
import {
|
|
9
|
+
import { createConfig } from './options';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Accessible from browser console.
|
|
13
|
+
*/
|
|
14
|
+
declare global {
|
|
15
|
+
const DX_LOG: Log;
|
|
16
|
+
}
|
|
10
17
|
|
|
11
18
|
/**
|
|
12
19
|
* Logging function.
|
|
@@ -17,6 +24,9 @@ type LogFunction = (message: string, context?: LogContext, meta?: CallMetadata)
|
|
|
17
24
|
* Logging methods.
|
|
18
25
|
*/
|
|
19
26
|
export interface LogMethods {
|
|
27
|
+
config: (options: LogOptions) => Log;
|
|
28
|
+
addProcessor: (processor: LogProcessor, addDefault?: boolean) => () => void;
|
|
29
|
+
|
|
20
30
|
trace: LogFunction;
|
|
21
31
|
debug: LogFunction;
|
|
22
32
|
verbose: LogFunction;
|
|
@@ -24,70 +34,56 @@ export interface LogMethods {
|
|
|
24
34
|
warn: LogFunction;
|
|
25
35
|
error: LogFunction;
|
|
26
36
|
catch: (error: Error | any, context?: LogContext, meta?: CallMetadata) => void;
|
|
27
|
-
|
|
28
|
-
stack: (message?: string, context?: never, meta?: CallMetadata) => void;
|
|
37
|
+
|
|
29
38
|
method: (arg0?: never, arg1?: never, meta?: CallMetadata) => MethodDecorator;
|
|
30
|
-
|
|
39
|
+
function: <F extends (...args: any[]) => any>(
|
|
31
40
|
name: string,
|
|
32
41
|
fn: F,
|
|
33
|
-
opts?: {
|
|
42
|
+
opts?: {
|
|
43
|
+
transformOutput?: (result: ReturnType<F>) => Promise<any> | any;
|
|
44
|
+
},
|
|
34
45
|
) => F;
|
|
46
|
+
|
|
47
|
+
break: () => void;
|
|
48
|
+
stack: (message?: string, context?: never, meta?: CallMetadata) => void;
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
/**
|
|
38
52
|
* Properties accessible on the logging function.
|
|
53
|
+
* @internal
|
|
39
54
|
*/
|
|
40
|
-
interface Log extends
|
|
41
|
-
|
|
42
|
-
addProcessor: (processor: LogProcessor) => void;
|
|
43
|
-
runtimeConfig: LogConfig;
|
|
55
|
+
export interface Log extends LogFunction, LogMethods {
|
|
56
|
+
readonly runtimeConfig: LogConfig;
|
|
44
57
|
}
|
|
45
58
|
|
|
59
|
+
/**
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
46
62
|
interface LogImp extends Log {
|
|
63
|
+
_id: string;
|
|
47
64
|
_config: LogConfig;
|
|
48
65
|
}
|
|
49
66
|
|
|
50
|
-
|
|
51
|
-
const log: LogImp = ((...params) => processLog(LogLevel.DEBUG, ...params)) as LogImp;
|
|
52
|
-
|
|
53
|
-
log._config = getConfig();
|
|
54
|
-
Object.defineProperty(log, 'runtimeConfig', { get: () => log._config });
|
|
55
|
-
|
|
56
|
-
log.addProcessor = (processor: LogProcessor) => {
|
|
57
|
-
if (DEFAULT_PROCESSORS.filter((p) => p === processor).length === 0) {
|
|
58
|
-
DEFAULT_PROCESSORS.push(processor);
|
|
59
|
-
}
|
|
60
|
-
if (log._config.processors.filter((p) => p === processor).length === 0) {
|
|
61
|
-
log._config.processors.push(processor);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// Set config.
|
|
66
|
-
log.config = (options: LogOptions) => {
|
|
67
|
-
log._config = getConfig(options);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// TODO(burdon): API to set context and separate error object.
|
|
71
|
-
// E.g., log.warn('failed', { key: 123 }, err);
|
|
72
|
-
|
|
73
|
-
log.trace = (...params) => processLog(LogLevel.TRACE, ...params);
|
|
74
|
-
log.debug = (...params) => processLog(LogLevel.DEBUG, ...params);
|
|
75
|
-
log.verbose = (...params) => processLog(LogLevel.VERBOSE, ...params);
|
|
76
|
-
log.info = (...params) => processLog(LogLevel.INFO, ...params);
|
|
77
|
-
log.warn = (...params) => processLog(LogLevel.WARN, ...params);
|
|
78
|
-
log.error = (...params) => processLog(LogLevel.ERROR, ...params);
|
|
67
|
+
let logCount = 0;
|
|
79
68
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Create a logging function with properties.
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
export const createLog = (): LogImp => {
|
|
74
|
+
// Default function.
|
|
75
|
+
const log: LogImp = ((...params) => processLog(LogLevel.DEBUG, ...params)) as LogImp;
|
|
85
76
|
|
|
86
|
-
|
|
87
|
-
|
|
77
|
+
// Add private properties.
|
|
78
|
+
Object.assign<LogImp, Partial<LogImp>>(log, {
|
|
79
|
+
_id: `log-${++logCount}`,
|
|
80
|
+
_config: createConfig(),
|
|
81
|
+
});
|
|
88
82
|
|
|
89
|
-
|
|
90
|
-
log
|
|
83
|
+
// TODO(burdon): Document.
|
|
84
|
+
Object.defineProperty(log, 'runtimeConfig', {
|
|
85
|
+
get: () => log._config,
|
|
86
|
+
});
|
|
91
87
|
|
|
92
88
|
/**
|
|
93
89
|
* Process the current log call.
|
|
@@ -99,16 +95,72 @@ const createLog = (): LogImp => {
|
|
|
99
95
|
meta?: CallMetadata,
|
|
100
96
|
error?: Error,
|
|
101
97
|
) => {
|
|
102
|
-
|
|
98
|
+
// TODO(burdon): Do the filter matching upstream (here) rather than in each processor?
|
|
99
|
+
log._config.processors.forEach((processor) =>
|
|
100
|
+
processor(log._config, {
|
|
101
|
+
level,
|
|
102
|
+
message,
|
|
103
|
+
context,
|
|
104
|
+
meta,
|
|
105
|
+
error,
|
|
106
|
+
}),
|
|
107
|
+
);
|
|
103
108
|
};
|
|
104
109
|
|
|
110
|
+
/**
|
|
111
|
+
* API.
|
|
112
|
+
*/
|
|
113
|
+
Object.assign<Log, LogMethods>(log, {
|
|
114
|
+
/**
|
|
115
|
+
* Update config.
|
|
116
|
+
* NOTE: Preserves any processors that were already added to this logger instance
|
|
117
|
+
* unless an explicit processor option is provided.
|
|
118
|
+
*/
|
|
119
|
+
config: ({ processor, ...options }) => {
|
|
120
|
+
const config = createConfig(options);
|
|
121
|
+
// TODO(burdon): This could be buggy since the behavior is not reentrant.
|
|
122
|
+
const processors = processor ? config.processors : log._config.processors;
|
|
123
|
+
log._config = { ...config, processors };
|
|
124
|
+
return log;
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Adds a processor to the logger.
|
|
129
|
+
*/
|
|
130
|
+
addProcessor: (processor) => {
|
|
131
|
+
if (log._config.processors.filter((p) => p === processor).length === 0) {
|
|
132
|
+
log._config.processors.push(processor);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return () => {
|
|
136
|
+
log._config.processors = log._config.processors.filter((p) => p !== processor);
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
trace: (...params) => processLog(LogLevel.TRACE, ...params),
|
|
141
|
+
debug: (...params) => processLog(LogLevel.DEBUG, ...params),
|
|
142
|
+
verbose: (...params) => processLog(LogLevel.VERBOSE, ...params),
|
|
143
|
+
info: (...params) => processLog(LogLevel.INFO, ...params),
|
|
144
|
+
warn: (...params) => processLog(LogLevel.WARN, ...params),
|
|
145
|
+
error: (...params) => processLog(LogLevel.ERROR, ...params),
|
|
146
|
+
catch: (error, context, meta) => processLog(LogLevel.ERROR, undefined, context, meta, error),
|
|
147
|
+
|
|
148
|
+
method: createMethodLogDecorator(log),
|
|
149
|
+
function: createFunctionLogDecorator(log),
|
|
150
|
+
|
|
151
|
+
break: () => log.info('-'.repeat(80)),
|
|
152
|
+
stack: (message, context, meta) => {
|
|
153
|
+
return processLog(LogLevel.INFO, `${message ?? 'Stack Dump'}\n${getFormattedStackTrace()}`, context, meta);
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
|
|
105
157
|
return log;
|
|
106
158
|
};
|
|
107
159
|
|
|
108
160
|
/**
|
|
109
161
|
* Global logging function.
|
|
110
162
|
*/
|
|
111
|
-
export const log: Log = ((globalThis as any).
|
|
163
|
+
export const log: Log = ((globalThis as any).DX_LOG ??= createLog());
|
|
112
164
|
|
|
113
165
|
const start = Date.now();
|
|
114
166
|
let last = start;
|
|
@@ -128,12 +180,4 @@ export const debug = (label?: any, args?: any) => {
|
|
|
128
180
|
last = Date.now();
|
|
129
181
|
};
|
|
130
182
|
|
|
131
|
-
/**
|
|
132
|
-
* Accessible from browser console.
|
|
133
|
-
*/
|
|
134
|
-
declare global {
|
|
135
|
-
// eslint-disable-next-line camelcase
|
|
136
|
-
const dx_log: Log;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
183
|
const getFormattedStackTrace = () => new Error().stack!.split('\n').slice(3).join('\n');
|
package/src/options.ts
CHANGED
|
@@ -7,37 +7,53 @@ import defaultsDeep from 'lodash.defaultsdeep';
|
|
|
7
7
|
import { type LogConfig, type LogFilter, LogLevel, type LogOptions, LogProcessorType, levels } from './config';
|
|
8
8
|
import { type LogProcessor } from './context';
|
|
9
9
|
import { loadOptions } from './platform';
|
|
10
|
-
import { CONSOLE_PROCESSOR, DEBUG_PROCESSOR
|
|
10
|
+
import { BROWSER_PROCESSOR, CONSOLE_PROCESSOR, DEBUG_PROCESSOR } from './processors';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Processor variants.
|
|
14
14
|
*/
|
|
15
|
-
export const processors:
|
|
15
|
+
export const processors: Record<string, LogProcessor> = {
|
|
16
16
|
[LogProcessorType.CONSOLE]: CONSOLE_PROCESSOR,
|
|
17
17
|
[LogProcessorType.BROWSER]: BROWSER_PROCESSOR,
|
|
18
18
|
[LogProcessorType.DEBUG]: DEBUG_PROCESSOR,
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const browser =
|
|
22
|
+
(typeof window !== 'undefined' || typeof navigator !== 'undefined') &&
|
|
23
|
+
!(typeof process !== 'undefined' && process?.env?.VITEST);
|
|
22
24
|
|
|
23
|
-
export const DEFAULT_PROCESSORS = [
|
|
25
|
+
export const DEFAULT_PROCESSORS = [browser ? BROWSER_PROCESSOR : CONSOLE_PROCESSOR];
|
|
24
26
|
|
|
27
|
+
const parseLogLevel = (level: string, defValue = LogLevel.WARN) => levels[level.toLowerCase()] ?? defValue;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
25
32
|
export const parseFilter = (filter: string | string[] | LogLevel): LogFilter[] => {
|
|
26
33
|
if (typeof filter === 'number') {
|
|
27
34
|
return [{ level: filter }];
|
|
28
35
|
}
|
|
29
36
|
|
|
30
|
-
const parseLogLevel = (level: string, defValue = LogLevel.WARN) => levels[level.toLowerCase()] ?? defValue;
|
|
31
|
-
|
|
32
37
|
const lines = typeof filter === 'string' ? filter.split(/,\s*/) : filter;
|
|
33
38
|
return lines.map((filter) => {
|
|
34
39
|
const [pattern, level] = filter.split(':');
|
|
35
|
-
return level
|
|
40
|
+
return level
|
|
41
|
+
? {
|
|
42
|
+
level: parseLogLevel(level),
|
|
43
|
+
pattern,
|
|
44
|
+
}
|
|
45
|
+
: {
|
|
46
|
+
level: parseLogLevel(pattern),
|
|
47
|
+
};
|
|
36
48
|
});
|
|
37
49
|
};
|
|
38
50
|
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
/**
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export const createConfig = (options?: LogOptions): LogConfig => {
|
|
55
|
+
// Node only.
|
|
56
|
+
const envOptions: LogOptions | undefined =
|
|
41
57
|
'process' in globalThis
|
|
42
58
|
? {
|
|
43
59
|
file: process!.env.LOG_CONFIG,
|
|
@@ -46,12 +62,12 @@ export const getConfig = (options?: LogOptions): LogConfig => {
|
|
|
46
62
|
}
|
|
47
63
|
: undefined;
|
|
48
64
|
|
|
49
|
-
const mergedOptions: LogOptions = defaultsDeep({}, loadOptions(
|
|
65
|
+
const mergedOptions: LogOptions = defaultsDeep({}, loadOptions(envOptions?.file), envOptions, options);
|
|
50
66
|
return {
|
|
51
67
|
options: mergedOptions,
|
|
52
68
|
filters: parseFilter(mergedOptions.filter ?? LogLevel.INFO),
|
|
53
69
|
captureFilters: parseFilter(mergedOptions.captureFilter ?? LogLevel.WARN),
|
|
54
|
-
processors: mergedOptions.processor ? [processors[mergedOptions.processor]] : DEFAULT_PROCESSORS,
|
|
70
|
+
processors: mergedOptions.processor ? [processors[mergedOptions.processor]] : [...DEFAULT_PROCESSORS],
|
|
55
71
|
prefix: mergedOptions.prefix,
|
|
56
72
|
};
|
|
57
73
|
};
|
package/src/platform/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { getDebugName, safariCheck } from '@dxos/util';
|
|
6
6
|
|
|
7
7
|
import { LogLevel } from '../config';
|
|
8
|
-
import {
|
|
8
|
+
import { type LogProcessor, getContextFromEntry, shouldLog } from '../context';
|
|
9
9
|
|
|
10
10
|
const getRelativeFilename = (filename: string) => {
|
|
11
11
|
// TODO(burdon): Hack uses "packages" as an anchor (pre-parse NX?)
|
|
@@ -74,6 +74,8 @@ const APP_BROWSER_PROCESSOR: LogProcessor = (config, entry) => {
|
|
|
74
74
|
if (context) {
|
|
75
75
|
if (Object.keys(context).length === 1 && 'error' in context) {
|
|
76
76
|
args.push(context.error);
|
|
77
|
+
} else if (Object.keys(context).length === 1 && 'err' in context) {
|
|
78
|
+
args.push(context.err);
|
|
77
79
|
} else {
|
|
78
80
|
args.push(context);
|
|
79
81
|
}
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import chalk from 'chalk';
|
|
6
5
|
import { inspect } from 'node:util';
|
|
7
6
|
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
8
9
|
import { getPrototypeSpecificInstanceId, pickBy } from '@dxos/util';
|
|
9
10
|
|
|
10
|
-
import { getRelativeFilename } from './common';
|
|
11
11
|
import { type LogConfig, LogLevel, shortLevelName } from '../config';
|
|
12
|
-
import {
|
|
12
|
+
import { type LogProcessor, getContextFromEntry, shouldLog } from '../context';
|
|
13
|
+
|
|
14
|
+
import { getRelativeFilename } from './common';
|
|
13
15
|
|
|
14
16
|
const LEVEL_COLORS: Record<LogLevel, typeof chalk.ForegroundColor> = {
|
|
15
17
|
[LogLevel.TRACE]: 'gray',
|
|
@@ -50,8 +52,10 @@ export const DEFAULT_FORMATTER: Formatter = (
|
|
|
50
52
|
let instance;
|
|
51
53
|
if (scope) {
|
|
52
54
|
const prototype = Object.getPrototypeOf(scope);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
if (prototype !== null) {
|
|
56
|
+
const id = getPrototypeSpecificInstanceId(scope);
|
|
57
|
+
instance = chalk.magentaBright(`${prototype.constructor.name}#${id}`);
|
|
58
|
+
}
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
const formattedTimestamp = config.options?.formatter?.timestamp ? new Date().toISOString() : undefined;
|
|
@@ -7,12 +7,14 @@ import { dirname } from 'node:path';
|
|
|
7
7
|
|
|
8
8
|
import { jsonlogify } from '@dxos/util';
|
|
9
9
|
|
|
10
|
-
import { getRelativeFilename } from './common';
|
|
11
10
|
import { type LogFilter, LogLevel } from '../config';
|
|
12
11
|
import { type LogProcessor, getContextFromEntry, shouldLog } from '../context';
|
|
13
12
|
|
|
13
|
+
import { getRelativeFilename } from './common';
|
|
14
|
+
|
|
14
15
|
// Amount of time to retry writing after encountering EAGAIN before giving up.
|
|
15
16
|
const EAGAIN_MAX_DURATION = 1000;
|
|
17
|
+
|
|
16
18
|
/**
|
|
17
19
|
* Create a file processor.
|
|
18
20
|
* @param path - Path to log file to create or append to, or existing open file descriptor e.g. stdout.
|
|
@@ -37,6 +39,7 @@ export const createFileProcessor = ({
|
|
|
37
39
|
if (!shouldLog(entry, filters)) {
|
|
38
40
|
return;
|
|
39
41
|
}
|
|
42
|
+
|
|
40
43
|
if (typeof pathOrFd === 'number') {
|
|
41
44
|
fd = pathOrFd;
|
|
42
45
|
} else {
|