logxpert 2.1.0 → 2.1.2
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 +20 -20
- package/README.md +119 -118
- package/index.d.ts +84 -83
- package/lib/mini.js +134 -134
- package/lib/sanitize.js +6 -7
- package/main.js +144 -136
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## Unreleased
|
|
4
|
-
- Fix TS types for dual CJS/ESM: `export =` + namespace in `index.d.ts`, dedicated `index.d.mts` for the ESM entry (`attw` clean)
|
|
5
|
-
- Rename `files` options with backward-compatible aliases: `prefix` (`appName`), `filePattern` (`filename`/`pattern`), `datePattern` (`filesName`/`dateFormat`); `%datePattern%` placeholder; `prefix` + `filePattern` now throws instead of silent precedence
|
|
6
|
-
- Default file `datePattern` is now `YYYY_MM_DD`
|
|
7
|
-
- License changed to `Apache-2.0`
|
|
8
|
-
|
|
9
|
-
## 2.0.0
|
|
10
|
-
- Replace `moment` with `dayjs`
|
|
11
|
-
- Add ESM entry (`main.mjs`) + `index.d.ts` types
|
|
12
|
-
- Add `log.setLevel/getLevel`, `LOG_LEVEL` env support
|
|
13
|
-
- Add `log.createLogger()` isolated instances and `log.child()`
|
|
14
|
-
- Add structured logging: objects, meta, `Error` stacks, `splat`
|
|
15
|
-
- `files.filename` option, input validation in `settings()`
|
|
16
|
-
- Fix license to `GPL-3.0-only`, add `exports`, `files`, `engines`
|
|
17
|
-
- Add tests (`node --test`) and CI
|
|
18
|
-
|
|
19
|
-
## 1.0.5
|
|
20
|
-
- Previous CJS-only release with `moment` + `winston`.
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
- Fix TS types for dual CJS/ESM: `export =` + namespace in `index.d.ts`, dedicated `index.d.mts` for the ESM entry (`attw` clean)
|
|
5
|
+
- Rename `files` options with backward-compatible aliases: `prefix` (`appName`), `filePattern` (`filename`/`pattern`), `datePattern` (`filesName`/`dateFormat`); `%datePattern%` placeholder; `prefix` + `filePattern` now throws instead of silent precedence
|
|
6
|
+
- Default file `datePattern` is now `YYYY_MM_DD`
|
|
7
|
+
- License changed to `Apache-2.0`
|
|
8
|
+
|
|
9
|
+
## 2.0.0
|
|
10
|
+
- Replace `moment` with `dayjs`
|
|
11
|
+
- Add ESM entry (`main.mjs`) + `index.d.ts` types
|
|
12
|
+
- Add `log.setLevel/getLevel`, `LOG_LEVEL` env support
|
|
13
|
+
- Add `log.createLogger()` isolated instances and `log.child()`
|
|
14
|
+
- Add structured logging: objects, meta, `Error` stacks, `splat`
|
|
15
|
+
- `files.filename` option, input validation in `settings()`
|
|
16
|
+
- Fix license to `GPL-3.0-only`, add `exports`, `files`, `engines`
|
|
17
|
+
- Add tests (`node --test`) and CI
|
|
18
|
+
|
|
19
|
+
## 1.0.5
|
|
20
|
+
- Previous CJS-only release with `moment` + `winston`.
|
package/README.md
CHANGED
|
@@ -1,118 +1,119 @@
|
|
|
1
|
-
# LogXpert
|
|
2
|
-
|
|
3
|
-
Colorful console logging for Node.js with optional daily file rotation.
|
|
4
|
-
|
|
5
|
-
- Zero heavy dependencies — built-in engine.
|
|
6
|
-
- Daily file rotation with retention, size limits and gzip.
|
|
7
|
-
- Per-level colors, lazy messages, child loggers, isolated instances.
|
|
8
|
-
- Works from JS and TS, CommonJS and ESM.
|
|
9
|
-
|
|
10
|
-
## Installation
|
|
11
|
-
|
|
12
|
-
```sh
|
|
13
|
-
npm install logxpert
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Requires Node.js `>=18`. Recommended minimum: Node.js 22 LTS. See [NODE_SUPPORT.md](NODE_SUPPORT.md) for the full support policy.
|
|
17
|
-
|
|
18
|
-
## Quick start
|
|
19
|
-
|
|
20
|
-
```js
|
|
21
|
-
const log = require('logxpert');
|
|
22
|
-
// or: import log from 'logxpert';
|
|
23
|
-
|
|
24
|
-
log('general message'); // shortcut for info
|
|
25
|
-
log.info('hello', { user: 1 }); // with metadata
|
|
26
|
-
log.error(new Error('boom')); // Errors print message + stack
|
|
27
|
-
log.debug(() => JSON.stringify(hugeObject)); // lazy: skipped if level disabled
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Levels: `error → warn → info → http → verbose → debug → silly` (default `debug`).
|
|
31
|
-
|
|
32
|
-
```js
|
|
33
|
-
log.setLevel('info'); // or via LOG_LEVEL env variable
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## File logging
|
|
37
|
-
|
|
38
|
-
```js
|
|
39
|
-
log.settings({ files: { folder: 'logs' } });
|
|
40
|
-
// → logs/logxpert-2026_10_08.log (prefix defaults to your package.json name)
|
|
41
|
-
|
|
42
|
-
log.settings({ files: { folder: 'logs', prefix: 'api' } });
|
|
43
|
-
// → logs/api-2026_10_08.log
|
|
44
|
-
|
|
45
|
-
// Full control (omit prefix when used):
|
|
46
|
-
log.settings({ files: { folder: 'logs', filePattern: 'app-%datePattern%.log' } });
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
`%datePattern%` is replaced by the date (`datePattern` defaults to `YYYY_MM_DD`). Combining `prefix` with `filePattern` throws — pick one.
|
|
50
|
-
|
|
51
|
-
```js
|
|
52
|
-
log.settings({
|
|
53
|
-
files: {
|
|
54
|
-
folder: 'logs',
|
|
55
|
-
runNumber: true, // off by default → app-2026_10_08-1.log, -2.log, ...
|
|
56
|
-
maxFile: '14d', // retention
|
|
57
|
-
maxSize: '20m', // rotate above this size
|
|
58
|
-
zippedArchive: true,
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
log.close(); // call on shutdown
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Console & instances
|
|
65
|
-
|
|
66
|
-
```js
|
|
67
|
-
log.settings({
|
|
68
|
-
console: {
|
|
69
|
-
enableTimestamp: true,
|
|
70
|
-
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
|
71
|
-
colorize: true,
|
|
72
|
-
colors: { info: 'blue', error: false }, // names, ANSI 0-255, or false per level
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Default colors: error red, warn yellow, info green, http magenta,
|
|
77
|
-
// verbose cyan, debug blue, silly gray. Only the [level] tag is colored.
|
|
78
|
-
|
|
79
|
-
const { createLogger } = require('logxpert');
|
|
80
|
-
const apiLog = createLogger({ level: 'info' }); // independent instance
|
|
81
|
-
|
|
82
|
-
const child = log.child({ service: 'api' }); // bound context
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Full configuration (copy-paste)
|
|
86
|
-
|
|
87
|
-
```js
|
|
88
|
-
log.settings({
|
|
89
|
-
level: 'debug', // or process.env.LOG_LEVEL
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
1
|
+
# LogXpert
|
|
2
|
+
|
|
3
|
+
Colorful console logging for Node.js with optional daily file rotation.
|
|
4
|
+
|
|
5
|
+
- Zero heavy dependencies — built-in engine.
|
|
6
|
+
- Daily file rotation with retention, size limits and gzip.
|
|
7
|
+
- Per-level colors, lazy messages, child loggers, isolated instances.
|
|
8
|
+
- Works from JS and TS, CommonJS and ESM.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm install logxpert
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Requires Node.js `>=18`. Recommended minimum: Node.js 22 LTS. See [NODE_SUPPORT.md](NODE_SUPPORT.md) for the full support policy.
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
const log = require('logxpert');
|
|
22
|
+
// or: import log from 'logxpert';
|
|
23
|
+
|
|
24
|
+
log('general message'); // shortcut for info
|
|
25
|
+
log.info('hello', { user: 1 }); // with metadata
|
|
26
|
+
log.error(new Error('boom')); // Errors print message + stack
|
|
27
|
+
log.debug(() => JSON.stringify(hugeObject)); // lazy: skipped if level disabled
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Levels: `error → warn → info → http → verbose → debug → silly` (default `debug`).
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
log.setLevel('info'); // or via LOG_LEVEL env variable
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## File logging
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
log.settings({ files: { folder: 'logs' } });
|
|
40
|
+
// → logs/logxpert-2026_10_08.log (prefix defaults to your package.json name)
|
|
41
|
+
|
|
42
|
+
log.settings({ files: { folder: 'logs', prefix: 'api' } });
|
|
43
|
+
// → logs/api-2026_10_08.log
|
|
44
|
+
|
|
45
|
+
// Full control (omit prefix when used):
|
|
46
|
+
log.settings({ files: { folder: 'logs', filePattern: 'app-%datePattern%.log' } });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`%datePattern%` is replaced by the date (`datePattern` defaults to `YYYY_MM_DD`). Combining `prefix` with `filePattern` throws — pick one.
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
log.settings({
|
|
53
|
+
files: {
|
|
54
|
+
folder: 'logs',
|
|
55
|
+
runNumber: true, // off by default → app-2026_10_08-1.log, -2.log, ...
|
|
56
|
+
maxFile: '14d', // retention
|
|
57
|
+
maxSize: '20m', // rotate above this size
|
|
58
|
+
zippedArchive: true,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
log.close(); // call on shutdown
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Console & instances
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
log.settings({
|
|
68
|
+
console: {
|
|
69
|
+
enableTimestamp: true,
|
|
70
|
+
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
|
71
|
+
colorize: true,
|
|
72
|
+
colors: { info: 'blue', error: false }, // names, ANSI 0-255, or false per level
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Default colors: error red, warn yellow, info green, http magenta,
|
|
77
|
+
// verbose cyan, debug blue, silly gray. Only the [level] tag is colored.
|
|
78
|
+
|
|
79
|
+
const { createLogger } = require('logxpert');
|
|
80
|
+
const apiLog = createLogger({ level: 'info' }); // independent instance
|
|
81
|
+
|
|
82
|
+
const child = log.child({ service: 'api' }); // bound context
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Full configuration (copy-paste)
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
log.settings({
|
|
89
|
+
level: 'debug', // or process.env.LOG_LEVEL
|
|
90
|
+
sanitize: true, // strip ANSI escapes and control chars; false = pass through untouched
|
|
91
|
+
console: {
|
|
92
|
+
enableTimestamp: true,
|
|
93
|
+
timestampFormat: 'YYYY-MM-DD HH:mm:ss',
|
|
94
|
+
timestampPrefix: '',
|
|
95
|
+
timestampSuffix: '',
|
|
96
|
+
colorize: true,
|
|
97
|
+
colors: { info: 'blue', warn: 208, error: false }
|
|
98
|
+
// enabled: false, // file-only logging: silence the console
|
|
99
|
+
},
|
|
100
|
+
files: {
|
|
101
|
+
folder: 'logs',
|
|
102
|
+
prefix: undefined, // defaults to your package.json name
|
|
103
|
+
// filePattern: 'app-%datePattern%.log', // full control (omit prefix if used)
|
|
104
|
+
datePattern: 'YYYY_MM_DD',
|
|
105
|
+
runNumber: false, // or true, or { separator: '-', padding: 0, startAt: 1 }
|
|
106
|
+
maxFile: '14d',
|
|
107
|
+
maxSize: '20m',
|
|
108
|
+
zippedArchive: false,
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Legacy aliases: `appName` (= `prefix`), `filename`/`pattern` (= `filePattern`), `filesName`/`dateFormat` (= `datePattern`).
|
|
114
|
+
|
|
115
|
+
Security: messages are stripped of ANSI escapes and control characters (except `\n`, `\t`); file patterns escaping the log folder (`..`, absolute paths) are rejected.
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
Apache-2.0. See [LICENSE](LICENSE).
|
package/index.d.ts
CHANGED
|
@@ -1,83 +1,84 @@
|
|
|
1
|
-
declare namespace log {
|
|
2
|
-
export type LogLevel = 'error' | 'warn' | 'info' | 'http' | 'verbose' | 'debug' | 'silly';
|
|
3
|
-
|
|
4
|
-
export type LevelColor = string | number | false | null;
|
|
5
|
-
|
|
6
|
-
export interface ConsoleOptions {
|
|
7
|
-
enabled?: boolean;
|
|
8
|
-
enableTimestamp?: boolean;
|
|
9
|
-
timestampFormat?: string;
|
|
10
|
-
timestampPrefix?: string;
|
|
11
|
-
timestampSuffix?: string;
|
|
12
|
-
colorize?: boolean;
|
|
13
|
-
colors?: Partial<Record<LogLevel, LevelColor>>;
|
|
14
|
-
level?: LogLevel;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface RunNumberOptions {
|
|
18
|
-
enabled?: boolean;
|
|
19
|
-
separator?: string;
|
|
20
|
-
padding?: number;
|
|
21
|
-
startAt?: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface FilesOptions {
|
|
25
|
-
folder?: string;
|
|
26
|
-
/** Preferred: date format for %DATE%. */
|
|
27
|
-
datePattern?: string;
|
|
28
|
-
/** @deprecated Use datePattern. */
|
|
29
|
-
filesName?: string;
|
|
30
|
-
dateFormat?: string;
|
|
31
|
-
/** Preferred: filename template containing %DATE%. */
|
|
32
|
-
filePattern?: string;
|
|
33
|
-
pattern?: string;
|
|
34
|
-
/** @deprecated Use filePattern. */
|
|
35
|
-
filename?: string;
|
|
36
|
-
/** Preferred: filename prefix used when no pattern is given. */
|
|
37
|
-
prefix?: string;
|
|
38
|
-
/** @deprecated Use prefix. */
|
|
39
|
-
appName?: string;
|
|
40
|
-
runNumber?: boolean | RunNumberOptions;
|
|
41
|
-
maxFile?: string;
|
|
42
|
-
maxFiles?: string;
|
|
43
|
-
maxSize?: string;
|
|
44
|
-
zippedArchive?: boolean;
|
|
45
|
-
level?: LogLevel;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface LogSettingsOptions {
|
|
49
|
-
console?: ConsoleOptions | false;
|
|
50
|
-
files?: FilesOptions;
|
|
51
|
-
level?: LogLevel;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
1
|
+
declare namespace log {
|
|
2
|
+
export type LogLevel = 'error' | 'warn' | 'info' | 'http' | 'verbose' | 'debug' | 'silly';
|
|
3
|
+
|
|
4
|
+
export type LevelColor = string | number | false | null;
|
|
5
|
+
|
|
6
|
+
export interface ConsoleOptions {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
enableTimestamp?: boolean;
|
|
9
|
+
timestampFormat?: string;
|
|
10
|
+
timestampPrefix?: string;
|
|
11
|
+
timestampSuffix?: string;
|
|
12
|
+
colorize?: boolean;
|
|
13
|
+
colors?: Partial<Record<LogLevel, LevelColor>>;
|
|
14
|
+
level?: LogLevel;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface RunNumberOptions {
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
separator?: string;
|
|
20
|
+
padding?: number;
|
|
21
|
+
startAt?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface FilesOptions {
|
|
25
|
+
folder?: string;
|
|
26
|
+
/** Preferred: date format for %DATE%. */
|
|
27
|
+
datePattern?: string;
|
|
28
|
+
/** @deprecated Use datePattern. */
|
|
29
|
+
filesName?: string;
|
|
30
|
+
dateFormat?: string;
|
|
31
|
+
/** Preferred: filename template containing %DATE%. */
|
|
32
|
+
filePattern?: string;
|
|
33
|
+
pattern?: string;
|
|
34
|
+
/** @deprecated Use filePattern. */
|
|
35
|
+
filename?: string;
|
|
36
|
+
/** Preferred: filename prefix used when no pattern is given. */
|
|
37
|
+
prefix?: string;
|
|
38
|
+
/** @deprecated Use prefix. */
|
|
39
|
+
appName?: string;
|
|
40
|
+
runNumber?: boolean | RunNumberOptions;
|
|
41
|
+
maxFile?: string;
|
|
42
|
+
maxFiles?: string;
|
|
43
|
+
maxSize?: string;
|
|
44
|
+
zippedArchive?: boolean;
|
|
45
|
+
level?: LogLevel;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface LogSettingsOptions {
|
|
49
|
+
console?: ConsoleOptions | false;
|
|
50
|
+
files?: FilesOptions;
|
|
51
|
+
level?: LogLevel;
|
|
52
|
+
sanitize?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ChildLogger {
|
|
56
|
+
error(message: unknown, ...meta: unknown[]): void;
|
|
57
|
+
warn(message: unknown, ...meta: unknown[]): void;
|
|
58
|
+
info(message: unknown, ...meta: unknown[]): void;
|
|
59
|
+
debug(message: unknown, ...meta: unknown[]): void;
|
|
60
|
+
log(level: LogLevel, message: unknown, ...meta: unknown[]): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface LogXpert {
|
|
64
|
+
(message: unknown, ...meta: unknown[]): void;
|
|
65
|
+
error(message: unknown, ...meta: unknown[]): void;
|
|
66
|
+
warn(message: unknown, ...meta: unknown[]): void;
|
|
67
|
+
info(message: unknown, ...meta: unknown[]): void;
|
|
68
|
+
debug(message: unknown, ...meta: unknown[]): void;
|
|
69
|
+
http(message: unknown, ...meta: unknown[]): void;
|
|
70
|
+
verbose(message: unknown, ...meta: unknown[]): void;
|
|
71
|
+
silly(message: unknown, ...meta: unknown[]): void;
|
|
72
|
+
log(level: LogLevel, message: unknown, ...meta: unknown[]): void;
|
|
73
|
+
settings(options?: LogSettingsOptions): void;
|
|
74
|
+
setLevel(level: LogLevel): void;
|
|
75
|
+
getLevel(): string;
|
|
76
|
+
child(meta?: Record<string, unknown>): ChildLogger;
|
|
77
|
+
close(): void;
|
|
78
|
+
createLogger(options?: LogSettingsOptions): LogXpert;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
declare const log: log.LogXpert;
|
|
83
|
+
|
|
84
|
+
export = log;
|
package/lib/mini.js
CHANGED
|
@@ -1,134 +1,134 @@
|
|
|
1
|
-
const LEVELS = {
|
|
2
|
-
error: 0,
|
|
3
|
-
warn: 1,
|
|
4
|
-
info: 2,
|
|
5
|
-
http: 3,
|
|
6
|
-
verbose: 4,
|
|
7
|
-
debug: 5,
|
|
8
|
-
silly: 6,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const COLORS = {
|
|
12
|
-
error: 31,
|
|
13
|
-
warn: 33,
|
|
14
|
-
info: 32,
|
|
15
|
-
http: 35,
|
|
16
|
-
verbose: 36,
|
|
17
|
-
debug: 34,
|
|
18
|
-
silly: 90,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const NAMED_COLORS = {
|
|
22
|
-
black: 30,
|
|
23
|
-
red: 31,
|
|
24
|
-
green: 32,
|
|
25
|
-
yellow: 33,
|
|
26
|
-
blue: 34,
|
|
27
|
-
magenta: 35,
|
|
28
|
-
cyan: 36,
|
|
29
|
-
white: 37,
|
|
30
|
-
gray: 90,
|
|
31
|
-
grey: 90,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
function resolveColorCode(value, level) {
|
|
35
|
-
if (value === undefined || value === null || value === false) return null;
|
|
36
|
-
if (typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 255) return value;
|
|
37
|
-
if (typeof value === 'string' && NAMED_COLORS[value.toLowerCase()] !== undefined) return NAMED_COLORS[value.toLowerCase()];
|
|
38
|
-
throw new Error(`Unknown color "${value}" for level "${level}". Use one of: ${Object.keys(NAMED_COLORS).join(', ')}, an ANSI code 0-255, or false to disable`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function resolveLevelColors(custom = {}) {
|
|
42
|
-
if (custom === null || typeof custom !== 'object' || Array.isArray(custom)) {
|
|
43
|
-
throw new Error('console.colors must be an object mapping level names to colors');
|
|
44
|
-
}
|
|
45
|
-
const map = {};
|
|
46
|
-
for (const level of Object.keys(COLORS)) {
|
|
47
|
-
if (custom[level] !== undefined) {
|
|
48
|
-
const code = resolveColorCode(custom[level], level);
|
|
49
|
-
if (code !== null) map[level] = code;
|
|
50
|
-
} else {
|
|
51
|
-
map[level] = COLORS[level];
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return map;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function colorizeLevel(level, text, colors = COLORS) {
|
|
58
|
-
const code = colors[level] ?? 0;
|
|
59
|
-
if (!code) return text;
|
|
60
|
-
return `\x1b[${code}m${text}\x1b[0m`;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
class NullTransport {
|
|
64
|
-
constructor() {
|
|
65
|
-
this.level = 'off';
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
write() {}
|
|
69
|
-
|
|
70
|
-
close() {}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
class ConsoleTransport {
|
|
74
|
-
constructor({ level, render } = {}) {
|
|
75
|
-
this.level = level;
|
|
76
|
-
this.render = render;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
write(entry) {
|
|
80
|
-
const line = this.render(entry);
|
|
81
|
-
const stream = entry.level === 'error' || entry.level === 'warn' ? process.stderr : process.stdout;
|
|
82
|
-
stream.write(line + '\n');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
close() {}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
class MiniLogger {
|
|
89
|
-
constructor({ level = 'debug' } = {}) {
|
|
90
|
-
this.level = level;
|
|
91
|
-
this.levels = LEVELS;
|
|
92
|
-
this.transports = [];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
add(transport) {
|
|
96
|
-
this.transports.push(transport);
|
|
97
|
-
return this;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
remove(transport) {
|
|
101
|
-
const i = this.transports.indexOf(transport);
|
|
102
|
-
if (i >= 0) this.transports.splice(i, 1);
|
|
103
|
-
try {
|
|
104
|
-
transport.close?.();
|
|
105
|
-
} catch {}
|
|
106
|
-
return this;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
enabled(level, transportLevel) {
|
|
110
|
-
const want = LEVELS[level];
|
|
111
|
-
const current = LEVELS[transportLevel ?? this.level];
|
|
112
|
-
return want !== undefined && current !== undefined && want <= current;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
log(level, message, ...meta) {
|
|
116
|
-
for (const t of [...this.transports]) {
|
|
117
|
-
if (this.enabled(level, t.level)) t.write({ level, message, meta });
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
child(meta = {}) {
|
|
122
|
-
const self = this;
|
|
123
|
-
const make = (level) => (message, ...args) => self.log(level, message, meta, ...args);
|
|
124
|
-
return {
|
|
125
|
-
error: make('error'),
|
|
126
|
-
warn: make('warn'),
|
|
127
|
-
info: make('info'),
|
|
128
|
-
debug: make('debug'),
|
|
129
|
-
log: (level, message, ...args) => self.log(level, message, meta, ...args),
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
module.exports = { LEVELS, ConsoleTransport, NullTransport, MiniLogger, colorizeLevel, resolveLevelColors, NAMED_COLORS };
|
|
1
|
+
const LEVELS = {
|
|
2
|
+
error: 0,
|
|
3
|
+
warn: 1,
|
|
4
|
+
info: 2,
|
|
5
|
+
http: 3,
|
|
6
|
+
verbose: 4,
|
|
7
|
+
debug: 5,
|
|
8
|
+
silly: 6,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const COLORS = {
|
|
12
|
+
error: 31,
|
|
13
|
+
warn: 33,
|
|
14
|
+
info: 32,
|
|
15
|
+
http: 35,
|
|
16
|
+
verbose: 36,
|
|
17
|
+
debug: 34,
|
|
18
|
+
silly: 90,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const NAMED_COLORS = {
|
|
22
|
+
black: 30,
|
|
23
|
+
red: 31,
|
|
24
|
+
green: 32,
|
|
25
|
+
yellow: 33,
|
|
26
|
+
blue: 34,
|
|
27
|
+
magenta: 35,
|
|
28
|
+
cyan: 36,
|
|
29
|
+
white: 37,
|
|
30
|
+
gray: 90,
|
|
31
|
+
grey: 90,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function resolveColorCode(value, level) {
|
|
35
|
+
if (value === undefined || value === null || value === false) return null;
|
|
36
|
+
if (typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 255) return value;
|
|
37
|
+
if (typeof value === 'string' && NAMED_COLORS[value.toLowerCase()] !== undefined) return NAMED_COLORS[value.toLowerCase()];
|
|
38
|
+
throw new Error(`Unknown color "${value}" for level "${level}". Use one of: ${Object.keys(NAMED_COLORS).join(', ')}, an ANSI code 0-255, or false to disable`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function resolveLevelColors(custom = {}) {
|
|
42
|
+
if (custom === null || typeof custom !== 'object' || Array.isArray(custom)) {
|
|
43
|
+
throw new Error('console.colors must be an object mapping level names to colors');
|
|
44
|
+
}
|
|
45
|
+
const map = {};
|
|
46
|
+
for (const level of Object.keys(COLORS)) {
|
|
47
|
+
if (custom[level] !== undefined) {
|
|
48
|
+
const code = resolveColorCode(custom[level], level);
|
|
49
|
+
if (code !== null) map[level] = code;
|
|
50
|
+
} else {
|
|
51
|
+
map[level] = COLORS[level];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return map;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function colorizeLevel(level, text, colors = COLORS) {
|
|
58
|
+
const code = colors[level] ?? 0;
|
|
59
|
+
if (!code) return text;
|
|
60
|
+
return `\x1b[${code}m${text}\x1b[0m`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
class NullTransport {
|
|
64
|
+
constructor() {
|
|
65
|
+
this.level = 'off';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
write() {}
|
|
69
|
+
|
|
70
|
+
close() {}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
class ConsoleTransport {
|
|
74
|
+
constructor({ level, render } = {}) {
|
|
75
|
+
this.level = level;
|
|
76
|
+
this.render = render;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
write(entry) {
|
|
80
|
+
const line = this.render(entry);
|
|
81
|
+
const stream = entry.level === 'error' || entry.level === 'warn' ? process.stderr : process.stdout;
|
|
82
|
+
stream.write(line + '\n');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
close() {}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
class MiniLogger {
|
|
89
|
+
constructor({ level = 'debug' } = {}) {
|
|
90
|
+
this.level = level;
|
|
91
|
+
this.levels = LEVELS;
|
|
92
|
+
this.transports = [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
add(transport) {
|
|
96
|
+
this.transports.push(transport);
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
remove(transport) {
|
|
101
|
+
const i = this.transports.indexOf(transport);
|
|
102
|
+
if (i >= 0) this.transports.splice(i, 1);
|
|
103
|
+
try {
|
|
104
|
+
transport.close?.();
|
|
105
|
+
} catch {}
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
enabled(level, transportLevel) {
|
|
110
|
+
const want = LEVELS[level];
|
|
111
|
+
const current = LEVELS[transportLevel ?? this.level];
|
|
112
|
+
return want !== undefined && current !== undefined && want <= current;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
log(level, message, ...meta) {
|
|
116
|
+
for (const t of [...this.transports]) {
|
|
117
|
+
if (this.enabled(level, t.level)) t.write({ level, message, meta });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
child(meta = {}) {
|
|
122
|
+
const self = this;
|
|
123
|
+
const make = (level) => (message, ...args) => self.log(level, message, meta, ...args);
|
|
124
|
+
return {
|
|
125
|
+
error: make('error'),
|
|
126
|
+
warn: make('warn'),
|
|
127
|
+
info: make('info'),
|
|
128
|
+
debug: make('debug'),
|
|
129
|
+
log: (level, message, ...args) => self.log(level, message, meta, ...args),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
module.exports = { LEVELS, ConsoleTransport, NullTransport, MiniLogger, colorizeLevel, resolveLevelColors, NAMED_COLORS };
|
package/lib/sanitize.js
CHANGED
|
@@ -10,29 +10,28 @@ function stripAnsi(str) {
|
|
|
10
10
|
let out = '';
|
|
11
11
|
let i = 0;
|
|
12
12
|
while (i < str.length) {
|
|
13
|
-
if (str[i] !== '\x1b') {
|
|
13
|
+
if (str[i] !== '\x1b' && str[i] !== '\x9b' && str[i] !== '\x9d') {
|
|
14
14
|
out += str[i];
|
|
15
15
|
i++;
|
|
16
16
|
continue;
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
if (next === ']') {
|
|
18
|
+
if (str[i] === '\x9d' || str[i + 1] === ']') {
|
|
20
19
|
let j = i + 2;
|
|
21
20
|
while (j < str.length) {
|
|
22
|
-
if (str[j] === '\x07') { j++; break; }
|
|
21
|
+
if (str[j] === '\x07' || str[j] === '\x9c') { j++; break; }
|
|
23
22
|
if (str[j] === '\x1b' && str[j + 1] === '\\') { j += 2; break; }
|
|
24
23
|
j++;
|
|
25
24
|
}
|
|
26
25
|
i = j;
|
|
27
|
-
} else if (
|
|
26
|
+
} else if (str[i] === '\x9b' || str[i + 1] === '[') {
|
|
28
27
|
let j = i + 2;
|
|
29
28
|
while (j < str.length && str[j] >= ' ' && str[j] <= '?') j++;
|
|
30
29
|
if (j < str.length) j++;
|
|
31
30
|
i = j;
|
|
32
|
-
} else if (
|
|
31
|
+
} else if (str[i + 1] === '(' || str[i + 1] === ')') {
|
|
33
32
|
i += 3;
|
|
34
33
|
} else {
|
|
35
|
-
i +=
|
|
34
|
+
i += str[i + 1] === undefined ? 1 : 2;
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
37
|
return out;
|
package/main.js
CHANGED
|
@@ -1,136 +1,144 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { MiniLogger, ConsoleTransport, NullTransport, colorizeLevel, resolveLevelColors } = require('./lib/mini');
|
|
4
|
-
const { FileTransport } = require('./lib/rotate');
|
|
5
|
-
const { DEFAULT_CONSOLE_FORMAT, compileTimestampFormatter } = require('./lib/time');
|
|
6
|
-
const { buildLine } = require('./lib/format');
|
|
7
|
-
const { assertLevel, sanitizeMessage } = require('./lib/sanitize');
|
|
8
|
-
const { normalizeFilesOptions } = require('./lib/files');
|
|
9
|
-
|
|
10
|
-
function normalizeConsoleOpts(input) {
|
|
11
|
-
if (input === false) return { enabled: false };
|
|
12
|
-
return input || {};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function buildConsoleTransport({ enabled = true, enableTimestamp = true, timestampFormat = DEFAULT_CONSOLE_FORMAT, timestampPrefix = '', timestampSuffix = '', colorize = true, colors, level } = {}) {
|
|
16
|
-
if (!enabled) return new NullTransport();
|
|
17
|
-
const stamp = enableTimestamp ? compileTimestampFormatter(timestampFormat) : null;
|
|
18
|
-
const palette = resolveLevelColors(colors);
|
|
19
|
-
const render = ({ level, message, meta }) => {
|
|
20
|
-
const timestamp = stamp ? `${timestampPrefix}${stamp()}${timestampSuffix}` : '';
|
|
21
|
-
const tag = colorize ? colorizeLevel(level, `[${level}]`, palette) : `[${level}]`;
|
|
22
|
-
return buildLine(timestamp, level, message, meta, tag);
|
|
23
|
-
};
|
|
24
|
-
return new ConsoleTransport({ level, render });
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function buildFileTransport({ folder, datePattern, filename, maxFiles, maxSize, zippedArchive, level }) {
|
|
28
|
-
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
29
|
-
return new FileTransport({
|
|
30
|
-
folder: path.normalize(folder),
|
|
31
|
-
filename,
|
|
32
|
-
datePattern,
|
|
33
|
-
zippedArchive,
|
|
34
|
-
maxSize,
|
|
35
|
-
maxFiles,
|
|
36
|
-
level,
|
|
37
|
-
render: ({ level, message, meta }) => buildLine(new Date().toISOString(), level, message, meta),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function createLoggerInstance(initial = {}) {
|
|
42
|
-
const globalLevel = process.env.LOG_LEVEL || initial.level || 'debug';
|
|
43
|
-
assertLevel(globalLevel);
|
|
44
|
-
|
|
45
|
-
const logger = new MiniLogger({ level: globalLevel });
|
|
46
|
-
|
|
47
|
-
let consoleTransport = buildConsoleTransport(normalizeConsoleOpts(initial.console));
|
|
48
|
-
consoleTransport.level = normalizeConsoleOpts(initial.console).level;
|
|
49
|
-
logger.add(consoleTransport);
|
|
50
|
-
|
|
51
|
-
let fileTransport = null;
|
|
52
|
-
let consoleOpts = { ...normalizeConsoleOpts(initial.console) };
|
|
53
|
-
let filesOpts = null;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
callable
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
callable.
|
|
108
|
-
callable.
|
|
109
|
-
|
|
110
|
-
callable.
|
|
111
|
-
callable.
|
|
112
|
-
callable.
|
|
113
|
-
callable.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { MiniLogger, ConsoleTransport, NullTransport, colorizeLevel, resolveLevelColors } = require('./lib/mini');
|
|
4
|
+
const { FileTransport } = require('./lib/rotate');
|
|
5
|
+
const { DEFAULT_CONSOLE_FORMAT, compileTimestampFormatter } = require('./lib/time');
|
|
6
|
+
const { buildLine } = require('./lib/format');
|
|
7
|
+
const { assertLevel, sanitizeMessage } = require('./lib/sanitize');
|
|
8
|
+
const { normalizeFilesOptions } = require('./lib/files');
|
|
9
|
+
|
|
10
|
+
function normalizeConsoleOpts(input) {
|
|
11
|
+
if (input === false) return { enabled: false };
|
|
12
|
+
return input || {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function buildConsoleTransport({ enabled = true, enableTimestamp = true, timestampFormat = DEFAULT_CONSOLE_FORMAT, timestampPrefix = '', timestampSuffix = '', colorize = true, colors, level } = {}) {
|
|
16
|
+
if (!enabled) return new NullTransport();
|
|
17
|
+
const stamp = enableTimestamp ? compileTimestampFormatter(timestampFormat) : null;
|
|
18
|
+
const palette = resolveLevelColors(colors);
|
|
19
|
+
const render = ({ level, message, meta }) => {
|
|
20
|
+
const timestamp = stamp ? `${timestampPrefix}${stamp()}${timestampSuffix}` : '';
|
|
21
|
+
const tag = colorize ? colorizeLevel(level, `[${level}]`, palette) : `[${level}]`;
|
|
22
|
+
return buildLine(timestamp, level, message, meta, tag);
|
|
23
|
+
};
|
|
24
|
+
return new ConsoleTransport({ level, render });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function buildFileTransport({ folder, datePattern, filename, maxFiles, maxSize, zippedArchive, level }) {
|
|
28
|
+
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
29
|
+
return new FileTransport({
|
|
30
|
+
folder: path.normalize(folder),
|
|
31
|
+
filename,
|
|
32
|
+
datePattern,
|
|
33
|
+
zippedArchive,
|
|
34
|
+
maxSize,
|
|
35
|
+
maxFiles,
|
|
36
|
+
level,
|
|
37
|
+
render: ({ level, message, meta }) => buildLine(new Date().toISOString(), level, message, meta),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function createLoggerInstance(initial = {}) {
|
|
42
|
+
const globalLevel = process.env.LOG_LEVEL || initial.level || 'debug';
|
|
43
|
+
assertLevel(globalLevel);
|
|
44
|
+
|
|
45
|
+
const logger = new MiniLogger({ level: globalLevel });
|
|
46
|
+
|
|
47
|
+
let consoleTransport = buildConsoleTransport(normalizeConsoleOpts(initial.console));
|
|
48
|
+
consoleTransport.level = normalizeConsoleOpts(initial.console).level;
|
|
49
|
+
logger.add(consoleTransport);
|
|
50
|
+
|
|
51
|
+
let fileTransport = null;
|
|
52
|
+
let consoleOpts = { ...normalizeConsoleOpts(initial.console) };
|
|
53
|
+
let filesOpts = null;
|
|
54
|
+
let sanitizeEnabled = initial.sanitize ?? true;
|
|
55
|
+
|
|
56
|
+
function applySettings(options = {}) {
|
|
57
|
+
if (options.level !== undefined) {
|
|
58
|
+
assertLevel(options.level);
|
|
59
|
+
logger.level = options.level;
|
|
60
|
+
}
|
|
61
|
+
if (options.sanitize !== undefined) {
|
|
62
|
+
if (typeof options.sanitize !== 'boolean') throw new Error('log.settings sanitize must be a boolean');
|
|
63
|
+
sanitizeEnabled = options.sanitize;
|
|
64
|
+
}
|
|
65
|
+
if (options.console !== undefined) {
|
|
66
|
+
const next = normalizeConsoleOpts(options.console);
|
|
67
|
+
if (next.level !== undefined && next.level !== null) assertLevel(next.level);
|
|
68
|
+
consoleOpts = { ...consoleOpts, ...next };
|
|
69
|
+
logger.remove(consoleTransport);
|
|
70
|
+
consoleTransport = buildConsoleTransport(consoleOpts);
|
|
71
|
+
consoleTransport.level = consoleOpts.level;
|
|
72
|
+
logger.add(consoleTransport);
|
|
73
|
+
}
|
|
74
|
+
if (options.files) {
|
|
75
|
+
const normalized = normalizeFilesOptions(options.files);
|
|
76
|
+
if (normalized.level !== undefined && normalized.level !== null) assertLevel(normalized.level);
|
|
77
|
+
filesOpts = normalized;
|
|
78
|
+
if (fileTransport) logger.remove(fileTransport);
|
|
79
|
+
fileTransport = buildFileTransport(normalized);
|
|
80
|
+
logger.add(fileTransport);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isEnabled(level) {
|
|
85
|
+
const want = logger.levels[level];
|
|
86
|
+
const current = logger.levels[logger.level];
|
|
87
|
+
return want !== undefined && current !== undefined && want <= current;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function write(level, message, ...meta) {
|
|
91
|
+
if (typeof message === 'function') {
|
|
92
|
+
if (!isEnabled(level)) return;
|
|
93
|
+
message = message();
|
|
94
|
+
}
|
|
95
|
+
if (message instanceof Error) {
|
|
96
|
+
const text = sanitizeEnabled ? sanitizeMessage(message.message) : message.message;
|
|
97
|
+
logger.log(level, text, { stack: message.stack, ...meta[0] });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
logger.log(level, sanitizeEnabled ? sanitizeMessage(message) : message, ...meta);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function callable(message, ...meta) {
|
|
104
|
+
write('info', message, ...meta);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
callable.error = (m, ...a) => write('error', m, ...a);
|
|
108
|
+
callable.warn = (m, ...a) => write('warn', m, ...a);
|
|
109
|
+
callable.info = (m, ...a) => write('info', m, ...a);
|
|
110
|
+
callable.debug = (m, ...a) => write('debug', m, ...a);
|
|
111
|
+
callable.http = (m, ...a) => write('http', m, ...a);
|
|
112
|
+
callable.verbose = (m, ...a) => write('verbose', m, ...a);
|
|
113
|
+
callable.silly = (m, ...a) => write('silly', m, ...a);
|
|
114
|
+
callable.log = (level, m, ...a) => { assertLevel(level); write(level, m, ...a); };
|
|
115
|
+
|
|
116
|
+
callable.settings = applySettings;
|
|
117
|
+
callable.setLevel = (level) => { assertLevel(level); logger.level = level; };
|
|
118
|
+
callable.getLevel = () => logger.level;
|
|
119
|
+
callable.child = (meta = {}) => {
|
|
120
|
+
const child = logger.child(meta);
|
|
121
|
+
return {
|
|
122
|
+
error: (m, ...a) => child.error(m, ...a),
|
|
123
|
+
warn: (m, ...a) => child.warn(m, ...a),
|
|
124
|
+
info: (m, ...a) => child.info(m, ...a),
|
|
125
|
+
debug: (m, ...a) => child.debug(m, ...a),
|
|
126
|
+
log: child.log.bind(child),
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
callable.close = () => {
|
|
130
|
+
if (fileTransport) { logger.remove(fileTransport); try { fileTransport.close?.(); } catch {} fileTransport = null; }
|
|
131
|
+
};
|
|
132
|
+
callable.createLogger = (opts = {}) => createLoggerInstance(opts);
|
|
133
|
+
callable._winston = logger;
|
|
134
|
+
|
|
135
|
+
if (initial.files) applySettings({ files: initial.files });
|
|
136
|
+
if (initial.console || initial.level || initial.sanitize !== undefined) {
|
|
137
|
+
applySettings({ console: initial.console, level: initial.level, sanitize: initial.sanitize });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return callable;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = createLoggerInstance();
|
|
144
|
+
module.exports.createLogger = createLoggerInstance;
|