@decohere/scribe 0.0.1-dev.20 → 0.0.1-dev.20261105.103
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/LICENSE +15 -0
- package/es6/src/console.adapter.js +21 -14
- package/es6/src/env.js +3 -4
- package/es6/src/errors.js +0 -2
- package/es6/src/index.js +3 -2
- package/es6/src/log-entry.adapter.js +49 -0
- package/es6/src/log-entry.js +79 -0
- package/es6/src/logger.adapter.js +42 -3
- package/es6/src/logger.factory.js +112 -11
- package/es6/src/logger.type.js +0 -2
- package/es6/src/redact.js +57 -0
- package/es6/src/testing/capture.adapter.js +17 -0
- package/es6/src/testing/index.js +1 -3
- package/es6/src/types.js +16 -6
- package/package.json +15 -3
- package/types/src/console.adapter.d.ts +1 -0
- package/types/src/env.d.ts +1 -1
- package/types/src/index.d.ts +3 -0
- package/types/src/log-entry.adapter.d.ts +20 -0
- package/types/src/log-entry.d.ts +38 -0
- package/types/src/logger.adapter.d.ts +31 -1
- package/types/src/logger.factory.d.ts +31 -2
- package/types/src/logger.type.d.ts +5 -0
- package/types/src/redact.d.ts +10 -0
- package/types/src/testing/capture.adapter.d.ts +14 -0
- package/types/src/testing/index.d.ts +1 -1
- package/types/src/types.d.ts +7 -0
- package/commonjs/src/console.adapter.js +0 -74
- package/commonjs/src/env.js +0 -94
- package/commonjs/src/errors.js +0 -14
- package/commonjs/src/index.js +0 -26
- package/commonjs/src/logger.adapter.js +0 -45
- package/commonjs/src/logger.factory.js +0 -78
- package/commonjs/src/logger.type.js +0 -6
- package/commonjs/src/testing/index.js +0 -6
- package/commonjs/src/types.js +0 -46
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Typesmiths
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
import { formatError, LogAdapter } from "./logger.adapter.js";
|
|
2
|
+
import { redact } from "./redact.js";
|
|
2
3
|
import { DefaultLogLevel, LogLevels } from "./types.js";
|
|
3
4
|
export class ConsoleAdapter extends LogAdapter {
|
|
4
5
|
configuredLevels;
|
|
5
6
|
configuredLogLevel = DefaultLogLevel;
|
|
6
7
|
configuredLogLevelValue = LogLevels.info;
|
|
8
|
+
redactionKeys = redact.fromOptions();
|
|
7
9
|
constructor(_options = {}){
|
|
8
10
|
super();
|
|
9
11
|
}
|
|
10
12
|
configure(scribeOptions) {
|
|
11
|
-
// Get merged log levels (default + custom) using parent class method
|
|
12
13
|
this.configuredLevels = this.getLogLevels(scribeOptions);
|
|
13
14
|
const logLevelStr = scribeOptions.logLevel ?? DefaultLogLevel;
|
|
14
15
|
this.configuredLogLevel = logLevelStr;
|
|
15
16
|
this.configuredLogLevelValue = this.configuredLevels[logLevelStr] ?? LogLevels.info;
|
|
17
|
+
this.redactionKeys = redact.fromOptions(scribeOptions.redactions);
|
|
16
18
|
}
|
|
17
19
|
getLogger(name) {
|
|
18
20
|
const loggerName = name || "default";
|
|
19
|
-
return this.createConsoleLogger(loggerName);
|
|
21
|
+
return this.createConsoleLogger(loggerName, {});
|
|
20
22
|
}
|
|
21
|
-
createConsoleLogger(name) {
|
|
22
|
-
// Use the levels configured during the configure() call
|
|
23
|
+
createConsoleLogger(name, bindings) {
|
|
23
24
|
const allLevels = this.configuredLevels;
|
|
24
25
|
const currentLevel = this.configuredLogLevel;
|
|
25
26
|
const threshold = this.configuredLogLevelValue;
|
|
27
|
+
const redactionKeys = this.redactionKeys;
|
|
28
|
+
const bound = Object.keys(bindings).length > 0 ? [
|
|
29
|
+
redact.object(bindings, redactionKeys)
|
|
30
|
+
] : [];
|
|
26
31
|
const baseLogger = {
|
|
27
32
|
get currentLevel () {
|
|
28
33
|
return currentLevel;
|
|
@@ -35,30 +40,32 @@ export class ConsoleAdapter extends LogAdapter {
|
|
|
35
40
|
const timestamp = new Date().toISOString();
|
|
36
41
|
let message;
|
|
37
42
|
if (typeof msg === "object") {
|
|
38
|
-
message = msg instanceof Error ? formatError(msg) : JSON.stringify(msg);
|
|
43
|
+
message = msg instanceof Error ? formatError(msg) : JSON.stringify(redact.object(msg, redactionKeys));
|
|
39
44
|
} else {
|
|
40
45
|
message = String(msg);
|
|
41
46
|
}
|
|
42
47
|
const logLine = `[${timestamp}] ${level.toUpperCase()} [${name}]: ${message}`;
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
const payload = [
|
|
49
|
+
...args.map((arg)=>redact.object(arg, redactionKeys)),
|
|
50
|
+
...bound
|
|
51
|
+
];
|
|
52
|
+
if (payload.length > 0) {
|
|
53
|
+
console.log(logLine, ...payload);
|
|
45
54
|
} else {
|
|
46
55
|
console.log(logLine);
|
|
47
56
|
}
|
|
48
57
|
};
|
|
49
58
|
const noop = ()=>{};
|
|
50
|
-
// Start with base logger and isLevelEnabled method
|
|
51
59
|
const logger = Object.assign(baseLogger, {
|
|
52
|
-
isLevelEnabled: (level)=>(allLevels[level] ?? 0) >= threshold
|
|
60
|
+
isLevelEnabled: (level)=>(allLevels[level] ?? 0) >= threshold,
|
|
61
|
+
child: (fields)=>this.createConsoleLogger(name, {
|
|
62
|
+
...bindings,
|
|
63
|
+
...fields
|
|
64
|
+
})
|
|
53
65
|
});
|
|
54
|
-
// Dynamically add all log level methods (default + custom)
|
|
55
|
-
// Levels below the configured threshold are patched to noop
|
|
56
66
|
for (const [levelName, levelValue] of Object.entries(allLevels)){
|
|
57
|
-
// biome-ignore lint/suspicious/noExplicitAny: Dynamic logger level creation requires any
|
|
58
67
|
logger[levelName] = levelValue >= threshold ? logFunction(levelName) : noop;
|
|
59
68
|
}
|
|
60
69
|
return logger;
|
|
61
70
|
}
|
|
62
71
|
}
|
|
63
|
-
|
|
64
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjcmliZS9zY3JpYmUvc3JjL2NvbnNvbGUuYWRhcHRlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmb3JtYXRFcnJvciwgTG9nQWRhcHRlciB9IGZyb20gXCIuL2xvZ2dlci5hZGFwdGVyLmpzXCI7XG5pbXBvcnQgdHlwZSB7IEJhc2VMb2dnZXIsIExvZ2dlciB9IGZyb20gXCIuL2xvZ2dlci50eXBlLmpzXCI7XG5pbXBvcnQge1xuXHREZWZhdWx0TG9nTGV2ZWwsXG5cdHR5cGUgTG9nQWRhcHRlck9wdGlvbnMsXG5cdExvZ0xldmVscyxcblx0dHlwZSBTY3JpYmVPcHRpb25zLFxufSBmcm9tIFwiLi90eXBlcy5qc1wiO1xuXG5leHBvcnQgdHlwZSBDb25zb2xlQWRhcHRlck9wdGlvbnMgPSB7fSAmIExvZ0FkYXB0ZXJPcHRpb25zO1xuXG5leHBvcnQgY2xhc3MgQ29uc29sZUFkYXB0ZXIgZXh0ZW5kcyBMb2dBZGFwdGVyIHtcblx0cHJpdmF0ZSBjb25maWd1cmVkTGV2ZWxzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xuXHRwcml2YXRlIGNvbmZpZ3VyZWRMb2dMZXZlbDogc3RyaW5nID0gRGVmYXVsdExvZ0xldmVsO1xuXHRwcml2YXRlIGNvbmZpZ3VyZWRMb2dMZXZlbFZhbHVlOiBudW1iZXIgPSBMb2dMZXZlbHMuaW5mbztcblxuXHRwdWJsaWMgY29uc3RydWN0b3IoX29wdGlvbnM6IENvbnNvbGVBZGFwdGVyT3B0aW9ucyA9IHt9KSB7XG5cdFx0c3VwZXIoKTtcblx0fVxuXG5cdHB1YmxpYyBjb25maWd1cmU8VCBleHRlbmRzIHN0cmluZyA9IG5ldmVyLCBDdXN0b21Pbmx5IGV4dGVuZHMgdHJ1ZSB8IGZhbHNlID0gZmFsc2U+KFxuXHRcdHNjcmliZU9wdGlvbnM6IFNjcmliZU9wdGlvbnM8VCwgQ3VzdG9tT25seT4sXG5cdCkge1xuXHRcdC8vIEdldCBtZXJnZWQgbG9nIGxldmVscyAoZGVmYXVsdCArIGN1c3RvbSkgdXNpbmcgcGFyZW50IGNsYXNzIG1ldGhvZFxuXHRcdHRoaXMuY29uZmlndXJlZExldmVscyA9IHRoaXMuZ2V0TG9nTGV2ZWxzKHNjcmliZU9wdGlvbnMpO1xuXHRcdGNvbnN0IGxvZ0xldmVsU3RyID0gc2NyaWJlT3B0aW9ucy5sb2dMZXZlbCA/PyBEZWZhdWx0TG9nTGV2ZWw7XG5cdFx0dGhpcy5jb25maWd1cmVkTG9nTGV2ZWwgPSBsb2dMZXZlbFN0cjtcblx0XHR0aGlzLmNvbmZpZ3VyZWRMb2dMZXZlbFZhbHVlID0gdGhpcy5jb25maWd1cmVkTGV2ZWxzW2xvZ0xldmVsU3RyXSA/PyBMb2dMZXZlbHMuaW5mbztcblx0fVxuXG5cdHB1YmxpYyBnZXRMb2dnZXI8VCBleHRlbmRzIHN0cmluZyA9IG5ldmVyLCBDdXN0b21Pbmx5IGV4dGVuZHMgdHJ1ZSB8IGZhbHNlID0gZmFsc2U+KFxuXHRcdG5hbWU/OiBzdHJpbmcsXG5cdCk6IExvZ2dlcjxULCBDdXN0b21Pbmx5PiB7XG5cdFx0Y29uc3QgbG9nZ2VyTmFtZSA9IG5hbWUgfHwgXCJkZWZhdWx0XCI7XG5cdFx0cmV0dXJuIHRoaXMuY3JlYXRlQ29uc29sZUxvZ2dlcjxULCBDdXN0b21Pbmx5Pihsb2dnZXJOYW1lKTtcblx0fVxuXG5cdHByaXZhdGUgY3JlYXRlQ29uc29sZUxvZ2dlcjxcblx0XHRUIGV4dGVuZHMgc3RyaW5nID0gbmV2ZXIsXG5cdFx0Q3VzdG9tT25seSBleHRlbmRzIHRydWUgfCBmYWxzZSA9IGZhbHNlLFxuXHQ+KG5hbWU6IHN0cmluZyk6IExvZ2dlcjxULCBDdXN0b21Pbmx5PiB7XG5cdFx0Ly8gVXNlIHRoZSBsZXZlbHMgY29uZmlndXJlZCBkdXJpbmcgdGhlIGNvbmZpZ3VyZSgpIGNhbGxcblx0XHRjb25zdCBhbGxMZXZlbHMgPSB0aGlzLmNvbmZpZ3VyZWRMZXZlbHM7XG5cdFx0Y29uc3QgY3VycmVudExldmVsID0gdGhpcy5jb25maWd1cmVkTG9nTGV2ZWw7XG5cdFx0Y29uc3QgdGhyZXNob2xkID0gdGhpcy5jb25maWd1cmVkTG9nTGV2ZWxWYWx1ZTtcblxuXHRcdGNvbnN0IGJhc2VMb2dnZXI6IEJhc2VMb2dnZXIgPSB7XG5cdFx0XHRnZXQgY3VycmVudExldmVsKCkge1xuXHRcdFx0XHRyZXR1cm4gY3VycmVudExldmVsO1xuXHRcdFx0fSxcblx0XHRcdGdldCBsb2dMZXZlbHMoKSB7XG5cdFx0XHRcdHJldHVybiBhbGxMZXZlbHM7XG5cdFx0XHR9LFxuXHRcdH07XG5cblx0XHRjb25zdCBsb2dGdW5jdGlvbiA9XG5cdFx0XHQobGV2ZWw6IHN0cmluZykgPT5cblx0XHRcdChtc2c6IHN0cmluZyB8IG51bWJlciB8IG9iamVjdCwgLi4uYXJnczogdW5rbm93bltdKSA9PiB7XG5cdFx0XHRcdGNvbnN0IHRpbWVzdGFtcCA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcblx0XHRcdFx0bGV0IG1lc3NhZ2U6IHN0cmluZztcblxuXHRcdFx0XHRpZiAodHlwZW9mIG1zZyA9PT0gXCJvYmplY3RcIikge1xuXHRcdFx0XHRcdG1lc3NhZ2UgPSBtc2cgaW5zdGFuY2VvZiBFcnJvciA/IGZvcm1hdEVycm9yKG1zZykgOiBKU09OLnN0cmluZ2lmeShtc2cpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdG1lc3NhZ2UgPSBTdHJpbmcobXNnKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNvbnN0IGxvZ0xpbmUgPSBgWyR7dGltZXN0YW1wfV0gJHtsZXZlbC50b1VwcGVyQ2FzZSgpfSBbJHtuYW1lfV06ICR7bWVzc2FnZX1gO1xuXG5cdFx0XHRcdGlmIChhcmdzLmxlbmd0aCA+IDApIHtcblx0XHRcdFx0XHRjb25zb2xlLmxvZyhsb2dMaW5lLCAuLi5hcmdzKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRjb25zb2xlLmxvZyhsb2dMaW5lKTtcblx0XHRcdFx0fVxuXHRcdFx0fTtcblxuXHRcdGNvbnN0IG5vb3AgPSAoKSA9PiB7fTtcblxuXHRcdC8vIFN0YXJ0IHdpdGggYmFzZSBsb2dnZXIgYW5kIGlzTGV2ZWxFbmFibGVkIG1ldGhvZFxuXHRcdGNvbnN0IGxvZ2dlciA9IE9iamVjdC5hc3NpZ24oYmFzZUxvZ2dlciwge1xuXHRcdFx0aXNMZXZlbEVuYWJsZWQ6IChsZXZlbDogc3RyaW5nKSA9PiAoYWxsTGV2ZWxzW2xldmVsXSA/PyAwKSA+PSB0aHJlc2hvbGQsXG5cdFx0fSk7XG5cblx0XHQvLyBEeW5hbWljYWxseSBhZGQgYWxsIGxvZyBsZXZlbCBtZXRob2RzIChkZWZhdWx0ICsgY3VzdG9tKVxuXHRcdC8vIExldmVscyBiZWxvdyB0aGUgY29uZmlndXJlZCB0aHJlc2hvbGQgYXJlIHBhdGNoZWQgdG8gbm9vcFxuXHRcdGZvciAoY29uc3QgW2xldmVsTmFtZSwgbGV2ZWxWYWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoYWxsTGV2ZWxzKSkge1xuXHRcdFx0Ly8gYmlvbWUtaWdub3JlIGxpbnQvc3VzcGljaW91cy9ub0V4cGxpY2l0QW55OiBEeW5hbWljIGxvZ2dlciBsZXZlbCBjcmVhdGlvbiByZXF1aXJlcyBhbnlcblx0XHRcdChsb2dnZXIgYXMgYW55KVtsZXZlbE5hbWVdID0gbGV2ZWxWYWx1ZSA+PSB0aHJlc2hvbGQgPyBsb2dGdW5jdGlvbihsZXZlbE5hbWUpIDogbm9vcDtcblx0XHR9XG5cblx0XHRyZXR1cm4gbG9nZ2VyIGFzIExvZ2dlcjxULCBDdXN0b21Pbmx5Pjtcblx0fVxufVxuIl0sIm5hbWVzIjpbImZvcm1hdEVycm9yIiwiTG9nQWRhcHRlciIsIkRlZmF1bHRMb2dMZXZlbCIsIkxvZ0xldmVscyIsIkNvbnNvbGVBZGFwdGVyIiwiY29uZmlndXJlZExldmVscyIsImNvbmZpZ3VyZWRMb2dMZXZlbCIsImNvbmZpZ3VyZWRMb2dMZXZlbFZhbHVlIiwiaW5mbyIsIl9vcHRpb25zIiwiY29uZmlndXJlIiwic2NyaWJlT3B0aW9ucyIsImdldExvZ0xldmVscyIsImxvZ0xldmVsU3RyIiwibG9nTGV2ZWwiLCJnZXRMb2dnZXIiLCJuYW1lIiwibG9nZ2VyTmFtZSIsImNyZWF0ZUNvbnNvbGVMb2dnZXIiLCJhbGxMZXZlbHMiLCJjdXJyZW50TGV2ZWwiLCJ0aHJlc2hvbGQiLCJiYXNlTG9nZ2VyIiwibG9nTGV2ZWxzIiwibG9nRnVuY3Rpb24iLCJsZXZlbCIsIm1zZyIsImFyZ3MiLCJ0aW1lc3RhbXAiLCJEYXRlIiwidG9JU09TdHJpbmciLCJtZXNzYWdlIiwiRXJyb3IiLCJKU09OIiwic3RyaW5naWZ5IiwiU3RyaW5nIiwibG9nTGluZSIsInRvVXBwZXJDYXNlIiwibGVuZ3RoIiwiY29uc29sZSIsImxvZyIsIm5vb3AiLCJsb2dnZXIiLCJPYmplY3QiLCJhc3NpZ24iLCJpc0xldmVsRW5hYmxlZCIsImxldmVsTmFtZSIsImxldmVsVmFsdWUiLCJlbnRyaWVzIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxXQUFXLEVBQUVDLFVBQVUsUUFBUSxzQkFBc0I7QUFFOUQsU0FDQ0MsZUFBZSxFQUVmQyxTQUFTLFFBRUgsYUFBYTtBQUlwQixPQUFPLE1BQU1DLHVCQUF1Qkg7SUFDM0JJLGlCQUF5QztJQUN6Q0MscUJBQTZCSixnQkFBZ0I7SUFDN0NLLDBCQUFrQ0osVUFBVUssSUFBSSxDQUFDO0lBRXpELFlBQW1CQyxXQUFrQyxDQUFDLENBQUMsQ0FBRTtRQUN4RCxLQUFLO0lBQ047SUFFT0MsVUFDTkMsYUFBMkMsRUFDMUM7UUFDRCxxRUFBcUU7UUFDckUsSUFBSSxDQUFDTixnQkFBZ0IsR0FBRyxJQUFJLENBQUNPLFlBQVksQ0FBQ0Q7UUFDMUMsTUFBTUUsY0FBY0YsY0FBY0csUUFBUSxJQUFJWjtRQUM5QyxJQUFJLENBQUNJLGtCQUFrQixHQUFHTztRQUMxQixJQUFJLENBQUNOLHVCQUF1QixHQUFHLElBQUksQ0FBQ0YsZ0JBQWdCLENBQUNRLFlBQVksSUFBSVYsVUFBVUssSUFBSTtJQUNwRjtJQUVPTyxVQUNOQyxJQUFhLEVBQ1c7UUFDeEIsTUFBTUMsYUFBYUQsUUFBUTtRQUMzQixPQUFPLElBQUksQ0FBQ0UsbUJBQW1CLENBQWdCRDtJQUNoRDtJQUVRQyxvQkFHTkYsSUFBWSxFQUF5QjtRQUN0Qyx3REFBd0Q7UUFDeEQsTUFBTUcsWUFBWSxJQUFJLENBQUNkLGdCQUFnQjtRQUN2QyxNQUFNZSxlQUFlLElBQUksQ0FBQ2Qsa0JBQWtCO1FBQzVDLE1BQU1lLFlBQVksSUFBSSxDQUFDZCx1QkFBdUI7UUFFOUMsTUFBTWUsYUFBeUI7WUFDOUIsSUFBSUYsZ0JBQWU7Z0JBQ2xCLE9BQU9BO1lBQ1I7WUFDQSxJQUFJRyxhQUFZO2dCQUNmLE9BQU9KO1lBQ1I7UUFDRDtRQUVBLE1BQU1LLGNBQ0wsQ0FBQ0MsUUFDRCxDQUFDQyxLQUErQixHQUFHQztnQkFDbEMsTUFBTUMsWUFBWSxJQUFJQyxPQUFPQyxXQUFXO2dCQUN4QyxJQUFJQztnQkFFSixJQUFJLE9BQU9MLFFBQVEsVUFBVTtvQkFDNUJLLFVBQVVMLGVBQWVNLFFBQVFoQyxZQUFZMEIsT0FBT08sS0FBS0MsU0FBUyxDQUFDUjtnQkFDcEUsT0FBTztvQkFDTkssVUFBVUksT0FBT1Q7Z0JBQ2xCO2dCQUVBLE1BQU1VLFVBQVUsQ0FBQyxDQUFDLEVBQUVSLFVBQVUsRUFBRSxFQUFFSCxNQUFNWSxXQUFXLEdBQUcsRUFBRSxFQUFFckIsS0FBSyxHQUFHLEVBQUVlLFNBQVM7Z0JBRTdFLElBQUlKLEtBQUtXLE1BQU0sR0FBRyxHQUFHO29CQUNwQkMsUUFBUUMsR0FBRyxDQUFDSixZQUFZVDtnQkFDekIsT0FBTztvQkFDTlksUUFBUUMsR0FBRyxDQUFDSjtnQkFDYjtZQUNEO1FBRUQsTUFBTUssT0FBTyxLQUFPO1FBRXBCLG1EQUFtRDtRQUNuRCxNQUFNQyxTQUFTQyxPQUFPQyxNQUFNLENBQUN0QixZQUFZO1lBQ3hDdUIsZ0JBQWdCLENBQUNwQixRQUFrQixBQUFDTixDQUFBQSxTQUFTLENBQUNNLE1BQU0sSUFBSSxDQUFBLEtBQU1KO1FBQy9EO1FBRUEsMkRBQTJEO1FBQzNELDREQUE0RDtRQUM1RCxLQUFLLE1BQU0sQ0FBQ3lCLFdBQVdDLFdBQVcsSUFBSUosT0FBT0ssT0FBTyxDQUFDN0IsV0FBWTtZQUNoRSx5RkFBeUY7WUFDeEZ1QixNQUFjLENBQUNJLFVBQVUsR0FBR0MsY0FBYzFCLFlBQVlHLFlBQVlzQixhQUFhTDtRQUNqRjtRQUVBLE9BQU9DO0lBQ1I7QUFDRCJ9
|
package/es6/src/env.js
CHANGED
|
@@ -17,10 +17,11 @@ const VALID_LEVELS = [
|
|
|
17
17
|
/**
|
|
18
18
|
* Reads the log level from environment variables.
|
|
19
19
|
* Checks LOG_LEVEL, SCRIBE_LOG_LEVEL, and LOGGING_LEVEL in order.
|
|
20
|
-
* Returns null if none are set.
|
|
20
|
+
* Returns null if none are set, or if the runtime has no `process` (browsers).
|
|
21
21
|
*/ export function getLogLevelFromEnv() {
|
|
22
|
+
const env = globalThis.process?.env;
|
|
22
23
|
for (const name of ENV_VAR_NAMES){
|
|
23
|
-
const value =
|
|
24
|
+
const value = env?.[name]?.trim().toLowerCase();
|
|
24
25
|
if (value) {
|
|
25
26
|
return value;
|
|
26
27
|
}
|
|
@@ -75,5 +76,3 @@ export function resolveLogLevel(arg) {
|
|
|
75
76
|
}
|
|
76
77
|
return defaultLogLevel;
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjcmliZS9zY3JpYmUvc3JjL2Vudi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IERlZmF1bHRMZXZlbHMgfSBmcm9tIFwiLi90eXBlcy5qc1wiO1xuXG4vKipcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlIG5hbWVzIGNoZWNrZWQgaW4gb3JkZXIgb2YgcHJlY2VkZW5jZS5cbiAqIFRoZSBmaXJzdCBub24tZW1wdHkgdmFsdWUgZm91bmQgaXMgdXNlZC5cbiAqL1xuY29uc3QgRU5WX1ZBUl9OQU1FUyA9IFtcIkxPR19MRVZFTFwiLCBcIlNDUklCRV9MT0dfTEVWRUxcIiwgXCJMT0dHSU5HX0xFVkVMXCJdIGFzIGNvbnN0O1xuXG5jb25zdCBWQUxJRF9MRVZFTFM6IERlZmF1bHRMZXZlbHNbXSA9IFtcImZhdGFsXCIsIFwiZXJyb3JcIiwgXCJ3YXJuXCIsIFwiaW5mb1wiLCBcImRlYnVnXCIsIFwidHJhY2VcIl07XG5cbi8qKlxuICogUmVhZHMgdGhlIGxvZyBsZXZlbCBmcm9tIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAqIENoZWNrcyBMT0dfTEVWRUwsIFNDUklCRV9MT0dfTEVWRUwsIGFuZCBMT0dHSU5HX0xFVkVMIGluIG9yZGVyLlxuICogUmV0dXJucyBudWxsIGlmIG5vbmUgYXJlIHNldC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvZ0xldmVsRnJvbUVudigpOiBzdHJpbmcgfCBudWxsIHtcblx0Zm9yIChjb25zdCBuYW1lIG9mIEVOVl9WQVJfTkFNRVMpIHtcblx0XHRjb25zdCB2YWx1ZSA9IHByb2Nlc3MuZW52W25hbWVdPy50cmltKCkudG9Mb3dlckNhc2UoKTtcblx0XHRpZiAodmFsdWUpIHtcblx0XHRcdHJldHVybiB2YWx1ZTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogUmVhZHMgYSBsb2ctbGV2ZWwgZmxhZyBmcm9tIGFyZ3YuXG4gKiBTdXBwb3J0czogLS1sb2ctbGV2ZWwgPHZhbHVlPiwgLWwgPHZhbHVlPiwgYW5kIC0tbG9nLWxldmVsPTx2YWx1ZT5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvZ0xldmVsRnJvbUFyZ3YoYXJndjogcmVhZG9ubHkgc3RyaW5nW10pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuXHRmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgYXJndi5sZW5ndGg7IGluZGV4ICs9IDEpIHtcblx0XHRjb25zdCBhcmcgPSBhcmd2W2luZGV4XTtcblx0XHRpZiAoYXJnID09PSBcIi0tbG9nLWxldmVsXCIgfHwgYXJnID09PSBcIi1sXCIpIHtcblx0XHRcdHJldHVybiBhcmd2W2luZGV4ICsgMV07XG5cdFx0fVxuXHRcdGlmIChhcmcuc3RhcnRzV2l0aChcIi0tbG9nLWxldmVsPVwiKSkge1xuXHRcdFx0cmV0dXJuIGFyZy5zbGljZShcIi0tbG9nLWxldmVsPVwiLmxlbmd0aCk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBhIHJlY29nbmlzZWQgZGVmYXVsdCBsb2cgbGV2ZWwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhbGlkTG9nTGV2ZWwobGV2ZWw6IHN0cmluZyk6IGxldmVsIGlzIERlZmF1bHRMZXZlbHMge1xuXHRyZXR1cm4gKFZBTElEX0xFVkVMUyBhcyBzdHJpbmdbXSkuaW5jbHVkZXMobGV2ZWwpO1xufVxuXG5leHBvcnQgdHlwZSBSZXNvbHZlTG9nTGV2ZWxPcHRpb25zID0ge1xuXHRleHBsaWNpdExvZ0xldmVsPzogc3RyaW5nIHwgbnVsbDtcblx0ZW52TG9nTGV2ZWw/OiBzdHJpbmcgfCBudWxsO1xuXHRkZWZhdWx0TG9nTGV2ZWw6IHN0cmluZztcbn07XG5cbi8qKlxuICogUmVzb2x2ZXMgbG9nIGxldmVsIHdpdGggcHJlY2VkZW5jZTogZXhwbGljaXQgPiBlbnYgPiBkZWZhdWx0LlxuICogSW52YWxpZCBleHBsaWNpdC9lbnYgbGV2ZWxzIGZhbGwgYmFjayB0byBkZWZhdWx0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUxvZ0xldmVsKGV4cGxpY2l0TG9nTGV2ZWw/OiBzdHJpbmcgfCBudWxsKTogc3RyaW5nIHwgbnVsbDtcbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlTG9nTGV2ZWwob3B0aW9uczogUmVzb2x2ZUxvZ0xldmVsT3B0aW9ucyk6IHN0cmluZztcbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlTG9nTGV2ZWwoYXJnPzogc3RyaW5nIHwgbnVsbCB8IFJlc29sdmVMb2dMZXZlbE9wdGlvbnMpOiBzdHJpbmcgfCBudWxsIHtcblx0aWYgKHR5cGVvZiBhcmcgPT09IFwic3RyaW5nXCIpIHtcblx0XHRpZiAoaXNWYWxpZExvZ0xldmVsKGFyZykpIHtcblx0XHRcdHJldHVybiBhcmc7XG5cdFx0fVxuXG5cdFx0Y29uc3QgZW52TG9nTGV2ZWwgPSBnZXRMb2dMZXZlbEZyb21FbnYoKTtcblx0XHRpZiAoZW52TG9nTGV2ZWwgIT0gbnVsbCAmJiBpc1ZhbGlkTG9nTGV2ZWwoZW52TG9nTGV2ZWwpKSB7XG5cdFx0XHRyZXR1cm4gZW52TG9nTGV2ZWw7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cblxuXHRpZiAoYXJnID09IG51bGwpIHtcblx0XHRjb25zdCBlbnZMb2dMZXZlbCA9IGdldExvZ0xldmVsRnJvbUVudigpO1xuXHRcdGlmIChlbnZMb2dMZXZlbCAhPSBudWxsICYmIGlzVmFsaWRMb2dMZXZlbChlbnZMb2dMZXZlbCkpIHtcblx0XHRcdHJldHVybiBlbnZMb2dMZXZlbDtcblx0XHR9XG5cblx0XHRyZXR1cm4gbnVsbDtcblx0fVxuXG5cdGNvbnN0IHsgZXhwbGljaXRMb2dMZXZlbCwgZW52TG9nTGV2ZWwsIGRlZmF1bHRMb2dMZXZlbCB9ID0gYXJnO1xuXHRpZiAoZXhwbGljaXRMb2dMZXZlbCAhPSBudWxsICYmIGlzVmFsaWRMb2dMZXZlbChleHBsaWNpdExvZ0xldmVsKSkge1xuXHRcdHJldHVybiBleHBsaWNpdExvZ0xldmVsO1xuXHR9XG5cblx0Y29uc3QgcmVzb2x2ZWRFbnZMb2dMZXZlbCA9IGVudkxvZ0xldmVsID8/IGdldExvZ0xldmVsRnJvbUVudigpO1xuXHRpZiAocmVzb2x2ZWRFbnZMb2dMZXZlbCAhPSBudWxsICYmIGlzVmFsaWRMb2dMZXZlbChyZXNvbHZlZEVudkxvZ0xldmVsKSkge1xuXHRcdHJldHVybiByZXNvbHZlZEVudkxvZ0xldmVsO1xuXHR9XG5cblx0cmV0dXJuIGRlZmF1bHRMb2dMZXZlbDtcbn1cbiJdLCJuYW1lcyI6WyJFTlZfVkFSX05BTUVTIiwiVkFMSURfTEVWRUxTIiwiZ2V0TG9nTGV2ZWxGcm9tRW52IiwibmFtZSIsInZhbHVlIiwicHJvY2VzcyIsImVudiIsInRyaW0iLCJ0b0xvd2VyQ2FzZSIsImdldExvZ0xldmVsRnJvbUFyZ3YiLCJhcmd2IiwiaW5kZXgiLCJsZW5ndGgiLCJhcmciLCJzdGFydHNXaXRoIiwic2xpY2UiLCJ1bmRlZmluZWQiLCJpc1ZhbGlkTG9nTGV2ZWwiLCJsZXZlbCIsImluY2x1ZGVzIiwicmVzb2x2ZUxvZ0xldmVsIiwiZW52TG9nTGV2ZWwiLCJleHBsaWNpdExvZ0xldmVsIiwiZGVmYXVsdExvZ0xldmVsIiwicmVzb2x2ZWRFbnZMb2dMZXZlbCJdLCJtYXBwaW5ncyI6IkFBRUE7OztDQUdDLEdBQ0QsTUFBTUEsZ0JBQWdCO0lBQUM7SUFBYTtJQUFvQjtDQUFnQjtBQUV4RSxNQUFNQyxlQUFnQztJQUFDO0lBQVM7SUFBUztJQUFRO0lBQVE7SUFBUztDQUFRO0FBRTFGOzs7O0NBSUMsR0FDRCxPQUFPLFNBQVNDO0lBQ2YsS0FBSyxNQUFNQyxRQUFRSCxjQUFlO1FBQ2pDLE1BQU1JLFFBQVFDLFFBQVFDLEdBQUcsQ0FBQ0gsS0FBSyxFQUFFSSxPQUFPQztRQUN4QyxJQUFJSixPQUFPO1lBQ1YsT0FBT0E7UUFDUjtJQUNEO0lBQ0EsT0FBTztBQUNSO0FBRUE7OztDQUdDLEdBQ0QsT0FBTyxTQUFTSyxvQkFBb0JDLElBQXVCO0lBQzFELElBQUssSUFBSUMsUUFBUSxHQUFHQSxRQUFRRCxLQUFLRSxNQUFNLEVBQUVELFNBQVMsRUFBRztRQUNwRCxNQUFNRSxNQUFNSCxJQUFJLENBQUNDLE1BQU07UUFDdkIsSUFBSUUsUUFBUSxpQkFBaUJBLFFBQVEsTUFBTTtZQUMxQyxPQUFPSCxJQUFJLENBQUNDLFFBQVEsRUFBRTtRQUN2QjtRQUNBLElBQUlFLElBQUlDLFVBQVUsQ0FBQyxpQkFBaUI7WUFDbkMsT0FBT0QsSUFBSUUsS0FBSyxDQUFDLGVBQWVILE1BQU07UUFDdkM7SUFDRDtJQUVBLE9BQU9JO0FBQ1I7QUFFQTs7Q0FFQyxHQUNELE9BQU8sU0FBU0MsZ0JBQWdCQyxLQUFhO0lBQzVDLE9BQU8sQUFBQ2pCLGFBQTBCa0IsUUFBUSxDQUFDRDtBQUM1QztBQWNBLE9BQU8sU0FBU0UsZ0JBQWdCUCxHQUE0QztJQUMzRSxJQUFJLE9BQU9BLFFBQVEsVUFBVTtRQUM1QixJQUFJSSxnQkFBZ0JKLE1BQU07WUFDekIsT0FBT0E7UUFDUjtRQUVBLE1BQU1RLGNBQWNuQjtRQUNwQixJQUFJbUIsZUFBZSxRQUFRSixnQkFBZ0JJLGNBQWM7WUFDeEQsT0FBT0E7UUFDUjtRQUVBLE9BQU87SUFDUjtJQUVBLElBQUlSLE9BQU8sTUFBTTtRQUNoQixNQUFNUSxjQUFjbkI7UUFDcEIsSUFBSW1CLGVBQWUsUUFBUUosZ0JBQWdCSSxjQUFjO1lBQ3hELE9BQU9BO1FBQ1I7UUFFQSxPQUFPO0lBQ1I7SUFFQSxNQUFNLEVBQUVDLGdCQUFnQixFQUFFRCxXQUFXLEVBQUVFLGVBQWUsRUFBRSxHQUFHVjtJQUMzRCxJQUFJUyxvQkFBb0IsUUFBUUwsZ0JBQWdCSyxtQkFBbUI7UUFDbEUsT0FBT0E7SUFDUjtJQUVBLE1BQU1FLHNCQUFzQkgsZUFBZW5CO0lBQzNDLElBQUlzQix1QkFBdUIsUUFBUVAsZ0JBQWdCTyxzQkFBc0I7UUFDeEUsT0FBT0E7SUFDUjtJQUVBLE9BQU9EO0FBQ1IifQ==
|
package/es6/src/errors.js
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
1
|
export class LoggingConfigurationError extends Error {
|
|
2
2
|
}
|
|
3
|
-
|
|
4
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjcmliZS9zY3JpYmUvc3JjL2Vycm9ycy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgY2xhc3MgTG9nZ2luZ0NvbmZpZ3VyYXRpb25FcnJvciBleHRlbmRzIEVycm9yIHt9XG4iXSwibmFtZXMiOlsiTG9nZ2luZ0NvbmZpZ3VyYXRpb25FcnJvciIsIkVycm9yIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLE1BQU1BLGtDQUFrQ0M7QUFBTyJ9
|
package/es6/src/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export * from "./console.adapter.js";
|
|
2
2
|
export * from "./env.js";
|
|
3
3
|
export * from "./errors.js";
|
|
4
|
+
export * from "./log-entry.adapter.js";
|
|
5
|
+
export * from "./log-entry.js";
|
|
4
6
|
export * from "./logger.adapter.js";
|
|
5
7
|
export * from "./logger.factory.js";
|
|
6
8
|
export * from "./logger.type.js";
|
|
9
|
+
export * from "./redact.js";
|
|
7
10
|
export * from "./types.js";
|
|
8
|
-
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjcmliZS9zY3JpYmUvc3JjL2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gXCIuL2NvbnNvbGUuYWRhcHRlci5qc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vZW52LmpzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9lcnJvcnMuanNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2xvZ2dlci5hZGFwdGVyLmpzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9sb2dnZXIuZmFjdG9yeS5qc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vbG9nZ2VyLnR5cGUuanNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3R5cGVzLmpzXCI7XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyx1QkFBdUI7QUFDckMsY0FBYyxXQUFXO0FBQ3pCLGNBQWMsY0FBYztBQUM1QixjQUFjLHNCQUFzQjtBQUNwQyxjQUFjLHNCQUFzQjtBQUNwQyxjQUFjLG1CQUFtQjtBQUNqQyxjQUFjLGFBQWEifQ==
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { logEntry } from "./log-entry.js";
|
|
2
|
+
import { LogAdapter } from "./logger.adapter.js";
|
|
3
|
+
import { redact } from "./redact.js";
|
|
4
|
+
import { DefaultLogLevel, LogLevels } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Base for adapters that write structured entries. It owns levels, the level
|
|
7
|
+
* threshold, `child`, and censoring the `redactions` keys; a subclass only
|
|
8
|
+
* writes each `LogEntry`.
|
|
9
|
+
*/ export class LogEntryAdapter extends LogAdapter {
|
|
10
|
+
levels = LogLevels;
|
|
11
|
+
level = DefaultLogLevel;
|
|
12
|
+
threshold = LogLevels.info;
|
|
13
|
+
redactionKeys = redact.fromOptions();
|
|
14
|
+
configure(scribeOptions) {
|
|
15
|
+
this.levels = this.getLogLevels(scribeOptions);
|
|
16
|
+
this.level = scribeOptions.logLevel ?? DefaultLogLevel;
|
|
17
|
+
this.threshold = this.levels[this.level] ?? LogLevels.info;
|
|
18
|
+
this.redactionKeys = redact.fromOptions(scribeOptions.redactions);
|
|
19
|
+
}
|
|
20
|
+
getLogger(name) {
|
|
21
|
+
return this.createLogger(name || "default", {});
|
|
22
|
+
}
|
|
23
|
+
createLogger(name, bindings) {
|
|
24
|
+
const { levels, level: currentLevel, threshold, redactionKeys } = this;
|
|
25
|
+
const baseLogger = {
|
|
26
|
+
get currentLevel () {
|
|
27
|
+
return currentLevel;
|
|
28
|
+
},
|
|
29
|
+
get logLevels () {
|
|
30
|
+
return levels;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const noop = ()=>{};
|
|
34
|
+
const methods = {};
|
|
35
|
+
for (const [level, value] of Object.entries(levels)){
|
|
36
|
+
methods[level] = value >= threshold ? (...args)=>this.write(logEntry.from(level, name, args, {
|
|
37
|
+
bindings,
|
|
38
|
+
redactionKeys
|
|
39
|
+
})) : noop;
|
|
40
|
+
}
|
|
41
|
+
return Object.assign(baseLogger, methods, {
|
|
42
|
+
isLevelEnabled: (level)=>(levels[level] ?? 0) >= threshold,
|
|
43
|
+
child: (fields)=>this.createLogger(name, {
|
|
44
|
+
...bindings,
|
|
45
|
+
...fields
|
|
46
|
+
})
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { serializeError } from "./logger.adapter.js";
|
|
2
|
+
import { redact } from "./redact.js";
|
|
3
|
+
function isFields(value) {
|
|
4
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
/** Serialize errors passed as fields (`{ error }`), so they keep their message and stack. */ function serializeErrors(fields) {
|
|
7
|
+
const out = {};
|
|
8
|
+
for (const [key, value] of Object.entries(fields)){
|
|
9
|
+
out[key] = value instanceof Error ? serializeError(value) : value;
|
|
10
|
+
}
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Builds an entry from a log call's arguments:
|
|
15
|
+
*
|
|
16
|
+
* - `log.info("text")`, `log.info(42)` → `msg`
|
|
17
|
+
* - `log.error(err)` → `msg` is `err.message`, `err` the serialized error
|
|
18
|
+
* - `log.info({ fields })`, `log.info({ fields }, "text")` → `fields` (a string
|
|
19
|
+
* `msg` field becomes the message)
|
|
20
|
+
* - `log.info("text", { fields })` → `msg` + `fields`
|
|
21
|
+
* - `log.error("text", err)` → `msg` + `err`
|
|
22
|
+
* - `log.info("text", value)` → `msg` + `fields.data`; any further arguments go
|
|
23
|
+
* in `fields.args`
|
|
24
|
+
*/ function from(level, name, [first, ...rest], { bindings, redactionKeys }) {
|
|
25
|
+
let msg;
|
|
26
|
+
let err;
|
|
27
|
+
let fields = {};
|
|
28
|
+
if (first instanceof Error) {
|
|
29
|
+
err = first;
|
|
30
|
+
msg = first.message;
|
|
31
|
+
} else if (isFields(first)) {
|
|
32
|
+
const { msg: fieldMsg, ...others } = first;
|
|
33
|
+
fields = others;
|
|
34
|
+
if (typeof fieldMsg === "string") {
|
|
35
|
+
msg = fieldMsg;
|
|
36
|
+
} else if (fieldMsg !== undefined) {
|
|
37
|
+
fields.msg = fieldMsg;
|
|
38
|
+
}
|
|
39
|
+
if (typeof rest[0] === "string") {
|
|
40
|
+
msg = rest.shift();
|
|
41
|
+
}
|
|
42
|
+
} else if (first !== undefined) {
|
|
43
|
+
msg = String(first);
|
|
44
|
+
}
|
|
45
|
+
const [second, ...extra] = rest;
|
|
46
|
+
if (second instanceof Error && err == null) {
|
|
47
|
+
err = second;
|
|
48
|
+
} else if (isFields(second)) {
|
|
49
|
+
fields = {
|
|
50
|
+
...fields,
|
|
51
|
+
...second
|
|
52
|
+
};
|
|
53
|
+
} else if (second !== undefined) {
|
|
54
|
+
fields.data = second;
|
|
55
|
+
}
|
|
56
|
+
if (extra.length > 0) {
|
|
57
|
+
fields.args = extra;
|
|
58
|
+
}
|
|
59
|
+
const allFields = serializeErrors({
|
|
60
|
+
...bindings,
|
|
61
|
+
...fields
|
|
62
|
+
});
|
|
63
|
+
const entry = {
|
|
64
|
+
level,
|
|
65
|
+
name,
|
|
66
|
+
fields: redactionKeys == null ? allFields : redact.object(allFields, redactionKeys)
|
|
67
|
+
};
|
|
68
|
+
if (msg !== undefined) {
|
|
69
|
+
entry.msg = msg;
|
|
70
|
+
}
|
|
71
|
+
if (err != null) {
|
|
72
|
+
const serialized = serializeError(err);
|
|
73
|
+
entry.err = redactionKeys == null ? serialized : redact.object(serialized, redactionKeys);
|
|
74
|
+
}
|
|
75
|
+
return entry;
|
|
76
|
+
}
|
|
77
|
+
export const logEntry = {
|
|
78
|
+
from
|
|
79
|
+
};
|
|
@@ -2,11 +2,52 @@ import { LogLevels } from "./types.js";
|
|
|
2
2
|
export function formatError(err) {
|
|
3
3
|
return err.stack ?? err.message;
|
|
4
4
|
}
|
|
5
|
+
/** How many causes deep `serializeError` follows by default. */ export const DefaultErrorCauseDepth = 3;
|
|
6
|
+
/**
|
|
7
|
+
* Plain-object form of an error for structured logs. An `Error` cause, or an
|
|
8
|
+
* `Error` in another own property, is serialized the same way, up to
|
|
9
|
+
* `causeDepth` levels; any other value is kept as it is.
|
|
10
|
+
*/ export function serializeError(err, causeDepth = DefaultErrorCauseDepth) {
|
|
11
|
+
const out = {
|
|
12
|
+
name: err.name,
|
|
13
|
+
message: err.message
|
|
14
|
+
};
|
|
15
|
+
if (err.stack != null) {
|
|
16
|
+
out.stack = err.stack;
|
|
17
|
+
}
|
|
18
|
+
for (const [key, value] of Object.entries(err)){
|
|
19
|
+
if (key === "cause" || key in out) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!(value instanceof Error)) {
|
|
23
|
+
out[key] = value;
|
|
24
|
+
} else if (causeDepth > 0) {
|
|
25
|
+
out[key] = serializeError(value, causeDepth - 1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const { cause } = err;
|
|
29
|
+
if (cause instanceof Error) {
|
|
30
|
+
if (causeDepth > 0) {
|
|
31
|
+
out.cause = serializeError(cause, causeDepth - 1);
|
|
32
|
+
}
|
|
33
|
+
} else if (cause !== undefined) {
|
|
34
|
+
out.cause = cause;
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
5
38
|
export class LogAdapter {
|
|
6
39
|
flush(cb) {
|
|
7
40
|
cb?.();
|
|
8
41
|
}
|
|
9
|
-
|
|
42
|
+
retire() {
|
|
43
|
+
// Console / no-op adapters have nothing to release.
|
|
44
|
+
}
|
|
45
|
+
async stop() {
|
|
46
|
+
await this[Symbol.asyncDispose]();
|
|
47
|
+
}
|
|
48
|
+
async [Symbol.asyncDispose]() {
|
|
49
|
+
// Console / no-op adapters have nothing to release.
|
|
50
|
+
}
|
|
10
51
|
getLogLevels(options) {
|
|
11
52
|
const { customOnly, customLevels } = options;
|
|
12
53
|
if (customOnly) {
|
|
@@ -23,5 +64,3 @@ export class LogAdapter {
|
|
|
23
64
|
return unique;
|
|
24
65
|
}
|
|
25
66
|
}
|
|
26
|
-
|
|
27
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjcmliZS9zY3JpYmUvc3JjL2xvZ2dlci5hZGFwdGVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgTG9nZ2VyIH0gZnJvbSBcIi4vbG9nZ2VyLnR5cGUuanNcIjtcbmltcG9ydCB7IExvZ0xldmVscywgdHlwZSBTY3JpYmVPcHRpb25zIH0gZnJvbSBcIi4vdHlwZXMuanNcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdEVycm9yKGVycjogRXJyb3IpOiBzdHJpbmcge1xuXHRyZXR1cm4gZXJyLnN0YWNrID8/IGVyci5tZXNzYWdlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIExvZ2dlckFkYXB0ZXIge1xuXHRjb25maWd1cmU8VCBleHRlbmRzIHN0cmluZyA9IG5ldmVyLCBDdXN0b21Pbmx5IGV4dGVuZHMgdHJ1ZSB8IGZhbHNlID0gZmFsc2U+KFxuXHRcdG9wdGlvbnM6IFNjcmliZU9wdGlvbnM8VCwgQ3VzdG9tT25seT4sXG5cdCk7XG5cdGdldExvZ2dlcjxUIGV4dGVuZHMgc3RyaW5nID0gbmV2ZXIsIEN1c3RvbU9ubHkgZXh0ZW5kcyB0cnVlIHwgZmFsc2UgPSBmYWxzZT4oXG5cdFx0bmFtZTogc3RyaW5nLFxuXHQpOiBMb2dnZXI8VCwgQ3VzdG9tT25seT47XG5cdGZsdXNoKGNiPzogKCkgPT4gdm9pZCk6IHZvaWQ7XG59XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBMb2dBZGFwdGVyIGltcGxlbWVudHMgTG9nZ2VyQWRhcHRlciB7XG5cdHB1YmxpYyBhYnN0cmFjdCBjb25maWd1cmU8VCBleHRlbmRzIHN0cmluZyA9IG5ldmVyLCBDdXN0b21Pbmx5IGV4dGVuZHMgdHJ1ZSB8IGZhbHNlID0gZmFsc2U+KFxuXHRcdG9wdGlvbnM6IFNjcmliZU9wdGlvbnM8VCwgQ3VzdG9tT25seT4sXG5cdCk7XG5cblx0cHVibGljIGFic3RyYWN0IGdldExvZ2dlcjxUIGV4dGVuZHMgc3RyaW5nID0gbmV2ZXIsIEN1c3RvbU9ubHkgZXh0ZW5kcyB0cnVlIHwgZmFsc2UgPSBmYWxzZT4oXG5cdFx0bmFtZTogc3RyaW5nLFxuXHQpOiBMb2dnZXI8VCwgQ3VzdG9tT25seT47XG5cblx0cHVibGljIGZsdXNoKGNiPzogKCkgPT4gdm9pZCk6IHZvaWQge1xuXHRcdGNiPy4oKTtcblx0fVxuXG5cdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9FeHBsaWNpdEFueTogR2VuZXJpYyB1dGlsaXR5IG1ldGhvZCBuZWVkcyBmbGV4aWJsZSB0eXBpbmdcblx0cHJvdGVjdGVkIGdldExvZ0xldmVscyhvcHRpb25zOiBTY3JpYmVPcHRpb25zPGFueSwgYW55Pik6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4ge1xuXHRcdGNvbnN0IHsgY3VzdG9tT25seSwgY3VzdG9tTGV2ZWxzIH0gPSBvcHRpb25zO1xuXHRcdGlmIChjdXN0b21Pbmx5KSB7XG5cdFx0XHRyZXR1cm4gY3VzdG9tTGV2ZWxzO1xuXHRcdH1cblx0XHRjb25zdCBsZXZlbHMgPSB0aGlzLmdldFVuaXF1ZUxldmVscyhMb2dMZXZlbHMsIGN1c3RvbUxldmVscyk7XG5cdFx0cmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhsZXZlbHMpO1xuXHR9XG5cblx0cHJvdGVjdGVkIGdldFVuaXF1ZUxldmVscyhcblx0XHRkZWZhdWx0TGV2ZWxzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+LFxuXHRcdGN1c3RvbUxldmVsczogUmVjb3JkPHN0cmluZywgbnVtYmVyPixcblx0KSB7XG5cdFx0Y29uc3QgZGVmYXVsdEVudHJpZXMgPSBPYmplY3QuZW50cmllcyhkZWZhdWx0TGV2ZWxzID8/IHt9KTtcblx0XHRjb25zdCBjdXN0b21FbnRyaWVzID0gT2JqZWN0LmVudHJpZXMoY3VzdG9tTGV2ZWxzID8/IHt9KTtcblx0XHRjb25zdCBkZWZhdWx0Tm90SW5DdXN0b20gPSBkZWZhdWx0RW50cmllcy5maWx0ZXIoXG5cdFx0XHQoW2RrXSkgPT4gY3VzdG9tRW50cmllcy5maW5kSW5kZXgoKFtja10pID0+IGNrID09PSBkaykgPT09IC0xLFxuXHRcdCk7XG5cblx0XHRjb25zdCB1bmlxdWUgPSBkZWZhdWx0Tm90SW5DdXN0b20uY29uY2F0KGN1c3RvbUVudHJpZXMpO1xuXHRcdHJldHVybiB1bmlxdWU7XG5cdH1cbn1cbiJdLCJuYW1lcyI6WyJMb2dMZXZlbHMiLCJmb3JtYXRFcnJvciIsImVyciIsInN0YWNrIiwibWVzc2FnZSIsIkxvZ0FkYXB0ZXIiLCJmbHVzaCIsImNiIiwiZ2V0TG9nTGV2ZWxzIiwib3B0aW9ucyIsImN1c3RvbU9ubHkiLCJjdXN0b21MZXZlbHMiLCJsZXZlbHMiLCJnZXRVbmlxdWVMZXZlbHMiLCJPYmplY3QiLCJmcm9tRW50cmllcyIsImRlZmF1bHRMZXZlbHMiLCJkZWZhdWx0RW50cmllcyIsImVudHJpZXMiLCJjdXN0b21FbnRyaWVzIiwiZGVmYXVsdE5vdEluQ3VzdG9tIiwiZmlsdGVyIiwiZGsiLCJmaW5kSW5kZXgiLCJjayIsInVuaXF1ZSIsImNvbmNhdCJdLCJtYXBwaW5ncyI6IkFBQ0EsU0FBU0EsU0FBUyxRQUE0QixhQUFhO0FBRTNELE9BQU8sU0FBU0MsWUFBWUMsR0FBVTtJQUNyQyxPQUFPQSxJQUFJQyxLQUFLLElBQUlELElBQUlFLE9BQU87QUFDaEM7QUFZQSxPQUFPLE1BQWVDO0lBU2RDLE1BQU1DLEVBQWUsRUFBUTtRQUNuQ0E7SUFDRDtJQUVBLDJGQUEyRjtJQUNqRkMsYUFBYUMsT0FBZ0MsRUFBMEI7UUFDaEYsTUFBTSxFQUFFQyxVQUFVLEVBQUVDLFlBQVksRUFBRSxHQUFHRjtRQUNyQyxJQUFJQyxZQUFZO1lBQ2YsT0FBT0M7UUFDUjtRQUNBLE1BQU1DLFNBQVMsSUFBSSxDQUFDQyxlQUFlLENBQUNiLFdBQVdXO1FBQy9DLE9BQU9HLE9BQU9DLFdBQVcsQ0FBQ0g7SUFDM0I7SUFFVUMsZ0JBQ1RHLGFBQXFDLEVBQ3JDTCxZQUFvQyxFQUNuQztRQUNELE1BQU1NLGlCQUFpQkgsT0FBT0ksT0FBTyxDQUFDRixpQkFBaUIsQ0FBQztRQUN4RCxNQUFNRyxnQkFBZ0JMLE9BQU9JLE9BQU8sQ0FBQ1AsZ0JBQWdCLENBQUM7UUFDdEQsTUFBTVMscUJBQXFCSCxlQUFlSSxNQUFNLENBQy9DLENBQUMsQ0FBQ0MsR0FBRyxHQUFLSCxjQUFjSSxTQUFTLENBQUMsQ0FBQyxDQUFDQyxHQUFHLEdBQUtBLE9BQU9GLFFBQVEsQ0FBQztRQUc3RCxNQUFNRyxTQUFTTCxtQkFBbUJNLE1BQU0sQ0FBQ1A7UUFDekMsT0FBT007SUFDUjtBQUNEIn0=
|
|
@@ -1,23 +1,81 @@
|
|
|
1
1
|
import { ConsoleAdapter } from "./console.adapter.js";
|
|
2
2
|
import { resolveLogLevel } from "./env.js";
|
|
3
3
|
import { LoggingConfigurationError } from "./errors.js";
|
|
4
|
+
import { logEntry } from "./log-entry.js";
|
|
4
5
|
import { DefaultLogLevel, DefaultRedactions } from "./types.js";
|
|
5
6
|
export class scribe {
|
|
6
7
|
loggerProvider;
|
|
8
|
+
/** True after `configure({ adapter })` — the constructor’s ConsoleAdapter is only a fallback. */ adapterConfigured = false;
|
|
9
|
+
defaultAdapterWarned = false;
|
|
10
|
+
tap;
|
|
7
11
|
static instance = new scribe();
|
|
8
12
|
static logger(name, customLevels) {
|
|
9
|
-
|
|
13
|
+
// Apply custom levels once against the active adapter; the live handle
|
|
14
|
+
// re-resolves the underlying logger on each use.
|
|
15
|
+
if (customLevels) {
|
|
16
|
+
scribe.instance.getLogger(name, customLevels);
|
|
17
|
+
}
|
|
18
|
+
return scribe.createLiveLogger(name);
|
|
10
19
|
}
|
|
11
20
|
static configure(configOptions) {
|
|
21
|
+
const previous = scribe.instance;
|
|
22
|
+
// Sync: stop writes into the old ThreadStream before a new worker starts.
|
|
23
|
+
previous.retire();
|
|
12
24
|
scribe.instance = new scribe();
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
scribe.instance.configure(configOptions);
|
|
26
|
+
// Async drain of the retired adapter (flush / end). Flux/App.dispose may
|
|
27
|
+
// have already done this; reconfigure without stop still needs it.
|
|
28
|
+
void previous.stop();
|
|
29
|
+
return (name)=>scribe.logger(name);
|
|
17
30
|
}
|
|
18
31
|
static flush(cb) {
|
|
19
32
|
scribe.instance.loggerProvider.flush(cb);
|
|
20
33
|
}
|
|
34
|
+
/** Synchronously stop accepting writes on the active adapter. */ static retire() {
|
|
35
|
+
scribe.instance.retire();
|
|
36
|
+
}
|
|
37
|
+
/** Drain the active adapter and release workers / destinations. */ static async stop() {
|
|
38
|
+
await scribe.instance.stop();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Module-level `const log = scribe.logger(...)` must follow a later
|
|
42
|
+
* `scribe.configure()` (CLI / Flux / HotReloadServer). Forward every use to
|
|
43
|
+
* the active adapter logger for `name`, and `child(fields)` to a live handle
|
|
44
|
+
* that adds `bindings`, so children follow a reconfigure too.
|
|
45
|
+
*/ static createLiveLogger(name, bindings = {}) {
|
|
46
|
+
const bound = Object.keys(bindings).length > 0;
|
|
47
|
+
const resolve = ()=>{
|
|
48
|
+
const root = scribe.instance.getLogger(name);
|
|
49
|
+
return bound ? root.child(bindings) : root;
|
|
50
|
+
};
|
|
51
|
+
return new Proxy({}, {
|
|
52
|
+
get (_target, prop) {
|
|
53
|
+
if (prop === "child") {
|
|
54
|
+
return (fields)=>scribe.createLiveLogger(name, {
|
|
55
|
+
...bindings,
|
|
56
|
+
...fields
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const underlying = resolve();
|
|
60
|
+
const value = Reflect.get(underlying, prop, underlying);
|
|
61
|
+
if (typeof value !== "function") {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
const method = value.bind(underlying);
|
|
65
|
+
const instance = scribe.instance;
|
|
66
|
+
if (instance.tap == null || typeof prop !== "string" || !Object.hasOwn(underlying.logLevels, prop) || !underlying.isLevelEnabled(prop)) {
|
|
67
|
+
return method;
|
|
68
|
+
}
|
|
69
|
+
return (...args)=>{
|
|
70
|
+
method(...args);
|
|
71
|
+
instance.notifyTap(prop, name ?? "default", args, bindings);
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
has (_target, prop) {
|
|
75
|
+
return Reflect.has(resolve(), prop);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
21
79
|
constructor(){
|
|
22
80
|
// Initialize with default console adapter
|
|
23
81
|
this.loggerProvider = new ConsoleAdapter();
|
|
@@ -25,13 +83,32 @@ export class scribe {
|
|
|
25
83
|
this.loggerProvider.configure(defaultOptions);
|
|
26
84
|
}
|
|
27
85
|
configure(configOptions) {
|
|
28
|
-
const { adapter, options } = configOptions;
|
|
86
|
+
const { adapter, options, tap } = configOptions;
|
|
87
|
+
const previous = this.loggerProvider;
|
|
88
|
+
if (previous !== adapter) {
|
|
89
|
+
previous.retire();
|
|
90
|
+
}
|
|
29
91
|
this.loggerProvider = adapter;
|
|
92
|
+
this.adapterConfigured = true;
|
|
93
|
+
this.tap = tap;
|
|
30
94
|
const defaultsAndOptions = this.mergeDefaults(options);
|
|
31
95
|
adapter.configure(defaultsAndOptions);
|
|
32
|
-
|
|
96
|
+
if (previous !== adapter) {
|
|
97
|
+
void previous.stop();
|
|
98
|
+
}
|
|
99
|
+
return (name)=>scribe.logger(name);
|
|
100
|
+
}
|
|
101
|
+
retire() {
|
|
102
|
+
this.loggerProvider.retire();
|
|
103
|
+
}
|
|
104
|
+
async stop() {
|
|
105
|
+
await this.loggerProvider.stop();
|
|
106
|
+
}
|
|
107
|
+
async [Symbol.asyncDispose]() {
|
|
108
|
+
await this.stop();
|
|
33
109
|
}
|
|
34
110
|
getLogger(name, customLevels) {
|
|
111
|
+
this.warnIfDefaultAdapter();
|
|
35
112
|
// If custom levels are provided, we need to reconfigure the adapter
|
|
36
113
|
if (customLevels) {
|
|
37
114
|
const currentOptions = this.mergeDefaults({
|
|
@@ -43,6 +120,30 @@ export class scribe {
|
|
|
43
120
|
this.supportsLevels(customLevels, logger);
|
|
44
121
|
return logger;
|
|
45
122
|
}
|
|
123
|
+
notifyTap(level, name, args, bindings) {
|
|
124
|
+
const tap = this.tap;
|
|
125
|
+
if (tap == null) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
tap(logEntry.from(level, name, args, {
|
|
130
|
+
bindings
|
|
131
|
+
}));
|
|
132
|
+
} catch (err) {
|
|
133
|
+
// Not swallowed: the logging call returns, the runtime reports the tap's error.
|
|
134
|
+
queueMicrotask(()=>{
|
|
135
|
+
throw err;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
warnIfDefaultAdapter() {
|
|
140
|
+
if (this.adapterConfigured || this.defaultAdapterWarned) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.defaultAdapterWarned = true;
|
|
144
|
+
// console.warn, not the stderr stream: the facade runs in browsers and Workers too.
|
|
145
|
+
console.warn("[scribe] No logger adapter configured; using the default ConsoleAdapter. " + "Configure an adapter at your composition root (for production, prefer " + "@decohere/scribe-pino → JSON on stdout). See " + "https://github.com/typesmiths/decohere/blob/main/projects/scribe/README.md");
|
|
146
|
+
}
|
|
46
147
|
supportsLevels(customLevels, logger) {
|
|
47
148
|
if (!customLevels) {
|
|
48
149
|
return;
|
|
@@ -57,12 +158,12 @@ export class scribe {
|
|
|
57
158
|
}
|
|
58
159
|
mergeDefaults(options) {
|
|
59
160
|
const logLevel = resolveLogLevel(options?.logLevel) ?? DefaultLogLevel;
|
|
161
|
+
// Resolved logLevel must win over options spread (invalid explicit values
|
|
162
|
+
// would otherwise stick).
|
|
60
163
|
return {
|
|
61
|
-
logLevel,
|
|
62
164
|
redactions: DefaultRedactions,
|
|
63
|
-
...options
|
|
165
|
+
...options,
|
|
166
|
+
logLevel
|
|
64
167
|
};
|
|
65
168
|
}
|
|
66
169
|
}
|
|
67
|
-
|
|
68
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjcmliZS9zY3JpYmUvc3JjL2xvZ2dlci5mYWN0b3J5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbnNvbGVBZGFwdGVyIH0gZnJvbSBcIi4vY29uc29sZS5hZGFwdGVyLmpzXCI7XG5pbXBvcnQgeyByZXNvbHZlTG9nTGV2ZWwgfSBmcm9tIFwiLi9lbnYuanNcIjtcbmltcG9ydCB7IExvZ2dpbmdDb25maWd1cmF0aW9uRXJyb3IgfSBmcm9tIFwiLi9lcnJvcnMuanNcIjtcbmltcG9ydCB0eXBlIHsgTG9nZ2VyQWRhcHRlciB9IGZyb20gXCIuL2xvZ2dlci5hZGFwdGVyLmpzXCI7XG5pbXBvcnQgdHlwZSB7IExvZ2dlciB9IGZyb20gXCIuL2xvZ2dlci50eXBlLmpzXCI7XG5pbXBvcnQgeyBEZWZhdWx0TG9nTGV2ZWwsIERlZmF1bHRSZWRhY3Rpb25zLCB0eXBlIFNjcmliZU9wdGlvbnMgfSBmcm9tIFwiLi90eXBlcy5qc1wiO1xuXG50eXBlIExvZ2dlckZhY3RvcnlPcHRpb25zPFxuXHRUIGV4dGVuZHMgc3RyaW5nID0gbmV2ZXIsXG5cdEN1c3RvbU9ubHkgZXh0ZW5kcyB0cnVlIHwgZmFsc2UgPSBmYWxzZSxcbj4gPSB7XG5cdG9wdGlvbnM/OiBTY3JpYmVPcHRpb25zPFQsIEN1c3RvbU9ubHk+O1xuXHRhZGFwdGVyOiBMb2dnZXJBZGFwdGVyO1xufTtcblxuZXhwb3J0IGNsYXNzIHNjcmliZSB7XG5cdHByaXZhdGUgbG9nZ2VyUHJvdmlkZXI6IExvZ2dlckFkYXB0ZXI7XG5cdHByaXZhdGUgc3RhdGljIGluc3RhbmNlOiBzY3JpYmUgPSBuZXcgc2NyaWJlKCk7XG5cblx0cHVibGljIHN0YXRpYyBsb2dnZXI8VCBleHRlbmRzIHN0cmluZyA9IG5ldmVyLCBDdXN0b21Pbmx5IGV4dGVuZHMgdHJ1ZSB8IGZhbHNlID0gZmFsc2U+KFxuXHRcdG5hbWU/OiBzdHJpbmcsXG5cdFx0Y3VzdG9tTGV2ZWxzPzoge1xuXHRcdFx0W2xldmVsIGluIFRdOiBudW1iZXI7XG5cdFx0fSxcblx0KTogTG9nZ2VyPFQsIEN1c3RvbU9ubHk+IHtcblx0XHRyZXR1cm4gc2NyaWJlLmluc3RhbmNlLmdldExvZ2dlcjxULCBDdXN0b21Pbmx5PihuYW1lLCBjdXN0b21MZXZlbHMpIGFzIExvZ2dlcjxcblx0XHRcdFQsXG5cdFx0XHRDdXN0b21Pbmx5XG5cdFx0Pjtcblx0fVxuXG5cdHB1YmxpYyBzdGF0aWMgY29uZmlndXJlPFQgZXh0ZW5kcyBzdHJpbmcgPSBuZXZlciwgQ3VzdG9tT25seSBleHRlbmRzIHRydWUgfCBmYWxzZSA9IGZhbHNlPihcblx0XHRjb25maWdPcHRpb25zOiBMb2dnZXJGYWN0b3J5T3B0aW9uczxULCBDdXN0b21Pbmx5Pixcblx0KSB7XG5cdFx0c2NyaWJlLmluc3RhbmNlID0gbmV3IHNjcmliZSgpO1xuXHRcdHJldHVybiBzY3JpYmUuaW5zdGFuY2UuY29uZmlndXJlPFQsIEN1c3RvbU9ubHk+KGNvbmZpZ09wdGlvbnMpO1xuXHR9XG5cblx0cHVibGljIHN0YXRpYyBnZXQgZXh0ZW5kKCkge1xuXHRcdHJldHVybiBzY3JpYmUuaW5zdGFuY2U7XG5cdH1cblxuXHRwdWJsaWMgc3RhdGljIGZsdXNoKGNiPzogKCkgPT4gdm9pZCk6IHZvaWQge1xuXHRcdHNjcmliZS5pbnN0YW5jZS5sb2dnZXJQcm92aWRlci5mbHVzaChjYik7XG5cdH1cblxuXHRwdWJsaWMgY29uc3RydWN0b3IoKSB7XG5cdFx0Ly8gSW5pdGlhbGl6ZSB3aXRoIGRlZmF1bHQgY29uc29sZSBhZGFwdGVyXG5cdFx0dGhpcy5sb2dnZXJQcm92aWRlciA9IG5ldyBDb25zb2xlQWRhcHRlcigpO1xuXHRcdGNvbnN0IGRlZmF1bHRPcHRpb25zID0gdGhpcy5tZXJnZURlZmF1bHRzKCk7XG5cdFx0dGhpcy5sb2dnZXJQcm92aWRlci5jb25maWd1cmUoZGVmYXVsdE9wdGlvbnMpO1xuXHR9XG5cblx0cHVibGljIGNvbmZpZ3VyZTxUIGV4dGVuZHMgc3RyaW5nID0gbmV2ZXIsIEN1c3RvbU9ubHkgZXh0ZW5kcyB0cnVlIHwgZmFsc2UgPSBmYWxzZT4oXG5cdFx0Y29uZmlnT3B0aW9uczogTG9nZ2VyRmFjdG9yeU9wdGlvbnM8VCwgQ3VzdG9tT25seT4sXG5cdCk6IChuYW1lPzogc3RyaW5nKSA9PiBMb2dnZXI8VCwgQ3VzdG9tT25seT4ge1xuXHRcdGNvbnN0IHsgYWRhcHRlciwgb3B0aW9ucyB9ID0gY29uZmlnT3B0aW9ucztcblx0XHR0aGlzLmxvZ2dlclByb3ZpZGVyID0gYWRhcHRlcjtcblx0XHRjb25zdCBkZWZhdWx0c0FuZE9wdGlvbnMgPSB0aGlzLm1lcmdlRGVmYXVsdHM8VCwgQ3VzdG9tT25seT4ob3B0aW9ucyk7XG5cdFx0YWRhcHRlci5jb25maWd1cmUoZGVmYXVsdHNBbmRPcHRpb25zKTtcblx0XHRyZXR1cm4gKG5hbWU/OiBzdHJpbmcpID0+IGFkYXB0ZXIuZ2V0TG9nZ2VyKG5hbWUpIGFzIExvZ2dlcjxULCBDdXN0b21Pbmx5Pjtcblx0fVxuXG5cdHB1YmxpYyBnZXRMb2dnZXI8VCBleHRlbmRzIHN0cmluZyA9IG5ldmVyLCBDdXN0b21Pbmx5IGV4dGVuZHMgdHJ1ZSB8IGZhbHNlID0gZmFsc2U+KFxuXHRcdG5hbWU/OiBzdHJpbmcsXG5cdFx0Y3VzdG9tTGV2ZWxzPzoge1xuXHRcdFx0W2xldmVsIGluIFRdOiBudW1iZXI7XG5cdFx0fSxcblx0KTogTG9nZ2VyPFQsIEN1c3RvbU9ubHk+IHtcblx0XHQvLyBJZiBjdXN0b20gbGV2ZWxzIGFyZSBwcm92aWRlZCwgd2UgbmVlZCB0byByZWNvbmZpZ3VyZSB0aGUgYWRhcHRlclxuXHRcdGlmIChjdXN0b21MZXZlbHMpIHtcblx0XHRcdGNvbnN0IGN1cnJlbnRPcHRpb25zID0gdGhpcy5tZXJnZURlZmF1bHRzKHsgY3VzdG9tTGV2ZWxzIH0pO1xuXHRcdFx0dGhpcy5sb2dnZXJQcm92aWRlci5jb25maWd1cmUoY3VycmVudE9wdGlvbnMpO1xuXHRcdH1cblxuXHRcdGNvbnN0IGxvZ2dlciA9IHRoaXMubG9nZ2VyUHJvdmlkZXIuZ2V0TG9nZ2VyKG5hbWUpIGFzIExvZ2dlcjxULCBDdXN0b21Pbmx5Pjtcblx0XHR0aGlzLnN1cHBvcnRzTGV2ZWxzKGN1c3RvbUxldmVscywgbG9nZ2VyKTtcblx0XHRyZXR1cm4gbG9nZ2VyO1xuXHR9XG5cblx0cHJpdmF0ZSBzdXBwb3J0c0xldmVsczxUIGV4dGVuZHMgc3RyaW5nID0gbmV2ZXIsIEN1c3RvbU9ubHkgZXh0ZW5kcyB0cnVlID0gdW5kZWZpbmVkPihcblx0XHRjdXN0b21MZXZlbHM6IHtcblx0XHRcdFtsZXZlbCBpbiBUXTogbnVtYmVyO1xuXHRcdH0sXG5cdFx0bG9nZ2VyOiBMb2dnZXI8VCwgQ3VzdG9tT25seT4sXG5cdCkge1xuXHRcdGlmICghY3VzdG9tTGV2ZWxzKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Y29uc3QgbWlzc2luZ0xldmVsID0gT2JqZWN0LmVudHJpZXMoY3VzdG9tTGV2ZWxzKS5maW5kKFxuXHRcdFx0KGtleSkgPT4gIWxvZ2dlci5sb2dMZXZlbHNba2V5LmF0KDApLnRvU3RyaW5nKCldLFxuXHRcdCk7XG5cblx0XHRpZiAobWlzc2luZ0xldmVsICE9IG51bGwpIHtcblx0XHRcdHRocm93IG5ldyBMb2dnaW5nQ29uZmlndXJhdGlvbkVycm9yKFxuXHRcdFx0XHRgQ3VycmVudCBsb2dnZXIgd2FzIG5vdCBjb25maWd1cmVkIGZvciBjdXN0b20gbGV2ZWwgJHttaXNzaW5nTGV2ZWx9LCB2YWxpZCBsZXZlbHMgYXJlOiAke0pTT04uc3RyaW5naWZ5KGxvZ2dlci5sb2dMZXZlbHMpfWAsXG5cdFx0XHQpO1xuXHRcdH1cblx0XHRyZXR1cm4geyBtaXNzaW5nTGV2ZWwgfTtcblx0fVxuXG5cdHByaXZhdGUgbWVyZ2VEZWZhdWx0czxUIGV4dGVuZHMgc3RyaW5nID0gbmV2ZXIsIEN1c3RvbU9ubHkgZXh0ZW5kcyB0cnVlIHwgZmFsc2UgPSBmYWxzZT4oXG5cdFx0b3B0aW9ucz86IFNjcmliZU9wdGlvbnM8VCwgQ3VzdG9tT25seT4sXG5cdCk6IFNjcmliZU9wdGlvbnM8VCwgQ3VzdG9tT25seT4ge1xuXHRcdGNvbnN0IGxvZ0xldmVsID0gcmVzb2x2ZUxvZ0xldmVsKG9wdGlvbnM/LmxvZ0xldmVsKSA/PyBEZWZhdWx0TG9nTGV2ZWw7XG5cdFx0cmV0dXJuIHsgbG9nTGV2ZWwsIHJlZGFjdGlvbnM6IERlZmF1bHRSZWRhY3Rpb25zLCAuLi5vcHRpb25zIH07XG5cdH1cbn1cbiJdLCJuYW1lcyI6WyJDb25zb2xlQWRhcHRlciIsInJlc29sdmVMb2dMZXZlbCIsIkxvZ2dpbmdDb25maWd1cmF0aW9uRXJyb3IiLCJEZWZhdWx0TG9nTGV2ZWwiLCJEZWZhdWx0UmVkYWN0aW9ucyIsInNjcmliZSIsImxvZ2dlclByb3ZpZGVyIiwiaW5zdGFuY2UiLCJsb2dnZXIiLCJuYW1lIiwiY3VzdG9tTGV2ZWxzIiwiZ2V0TG9nZ2VyIiwiY29uZmlndXJlIiwiY29uZmlnT3B0aW9ucyIsImV4dGVuZCIsImZsdXNoIiwiY2IiLCJkZWZhdWx0T3B0aW9ucyIsIm1lcmdlRGVmYXVsdHMiLCJhZGFwdGVyIiwib3B0aW9ucyIsImRlZmF1bHRzQW5kT3B0aW9ucyIsImN1cnJlbnRPcHRpb25zIiwic3VwcG9ydHNMZXZlbHMiLCJtaXNzaW5nTGV2ZWwiLCJPYmplY3QiLCJlbnRyaWVzIiwiZmluZCIsImtleSIsImxvZ0xldmVscyIsImF0IiwidG9TdHJpbmciLCJKU09OIiwic3RyaW5naWZ5IiwibG9nTGV2ZWwiLCJyZWRhY3Rpb25zIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxjQUFjLFFBQVEsdUJBQXVCO0FBQ3RELFNBQVNDLGVBQWUsUUFBUSxXQUFXO0FBQzNDLFNBQVNDLHlCQUF5QixRQUFRLGNBQWM7QUFHeEQsU0FBU0MsZUFBZSxFQUFFQyxpQkFBaUIsUUFBNEIsYUFBYTtBQVVwRixPQUFPLE1BQU1DO0lBQ0pDLGVBQThCO0lBQ3RDLE9BQWVDLFdBQW1CLElBQUlGLFNBQVM7SUFFL0MsT0FBY0csT0FDYkMsSUFBYSxFQUNiQyxZQUVDLEVBQ3VCO1FBQ3hCLE9BQU9MLE9BQU9FLFFBQVEsQ0FBQ0ksU0FBUyxDQUFnQkYsTUFBTUM7SUFJdkQ7SUFFQSxPQUFjRSxVQUNiQyxhQUFrRCxFQUNqRDtRQUNEUixPQUFPRSxRQUFRLEdBQUcsSUFBSUY7UUFDdEIsT0FBT0EsT0FBT0UsUUFBUSxDQUFDSyxTQUFTLENBQWdCQztJQUNqRDtJQUVBLFdBQWtCQyxTQUFTO1FBQzFCLE9BQU9ULE9BQU9FLFFBQVE7SUFDdkI7SUFFQSxPQUFjUSxNQUFNQyxFQUFlLEVBQVE7UUFDMUNYLE9BQU9FLFFBQVEsQ0FBQ0QsY0FBYyxDQUFDUyxLQUFLLENBQUNDO0lBQ3RDO0lBRUEsYUFBcUI7UUFDcEIsMENBQTBDO1FBQzFDLElBQUksQ0FBQ1YsY0FBYyxHQUFHLElBQUlOO1FBQzFCLE1BQU1pQixpQkFBaUIsSUFBSSxDQUFDQyxhQUFhO1FBQ3pDLElBQUksQ0FBQ1osY0FBYyxDQUFDTSxTQUFTLENBQUNLO0lBQy9CO0lBRU9MLFVBQ05DLGFBQWtELEVBQ1A7UUFDM0MsTUFBTSxFQUFFTSxPQUFPLEVBQUVDLE9BQU8sRUFBRSxHQUFHUDtRQUM3QixJQUFJLENBQUNQLGNBQWMsR0FBR2E7UUFDdEIsTUFBTUUscUJBQXFCLElBQUksQ0FBQ0gsYUFBYSxDQUFnQkU7UUFDN0RELFFBQVFQLFNBQVMsQ0FBQ1M7UUFDbEIsT0FBTyxDQUFDWixPQUFrQlUsUUFBUVIsU0FBUyxDQUFDRjtJQUM3QztJQUVPRSxVQUNORixJQUFhLEVBQ2JDLFlBRUMsRUFDdUI7UUFDeEIsb0VBQW9FO1FBQ3BFLElBQUlBLGNBQWM7WUFDakIsTUFBTVksaUJBQWlCLElBQUksQ0FBQ0osYUFBYSxDQUFDO2dCQUFFUjtZQUFhO1lBQ3pELElBQUksQ0FBQ0osY0FBYyxDQUFDTSxTQUFTLENBQUNVO1FBQy9CO1FBRUEsTUFBTWQsU0FBUyxJQUFJLENBQUNGLGNBQWMsQ0FBQ0ssU0FBUyxDQUFDRjtRQUM3QyxJQUFJLENBQUNjLGNBQWMsQ0FBQ2IsY0FBY0Y7UUFDbEMsT0FBT0E7SUFDUjtJQUVRZSxlQUNQYixZQUVDLEVBQ0RGLE1BQTZCLEVBQzVCO1FBQ0QsSUFBSSxDQUFDRSxjQUFjO1lBQ2xCO1FBQ0Q7UUFFQSxNQUFNYyxlQUFlQyxPQUFPQyxPQUFPLENBQUNoQixjQUFjaUIsSUFBSSxDQUNyRCxDQUFDQyxNQUFRLENBQUNwQixPQUFPcUIsU0FBUyxDQUFDRCxJQUFJRSxFQUFFLENBQUMsR0FBR0MsUUFBUSxHQUFHO1FBR2pELElBQUlQLGdCQUFnQixNQUFNO1lBQ3pCLE1BQU0sSUFBSXRCLDBCQUNULENBQUMsbURBQW1ELEVBQUVzQixhQUFhLG9CQUFvQixFQUFFUSxLQUFLQyxTQUFTLENBQUN6QixPQUFPcUIsU0FBUyxHQUFHO1FBRTdIO1FBQ0EsT0FBTztZQUFFTDtRQUFhO0lBQ3ZCO0lBRVFOLGNBQ1BFLE9BQXNDLEVBQ1A7UUFDL0IsTUFBTWMsV0FBV2pDLGdCQUFnQm1CLFNBQVNjLGFBQWEvQjtRQUN2RCxPQUFPO1lBQUUrQjtZQUFVQyxZQUFZL0I7WUFBbUIsR0FBR2dCLE9BQU87UUFBQztJQUM5RDtBQUNEIn0=
|
package/es6/src/logger.type.js
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
1
|
export { };
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjcmliZS9zY3JpYmUvc3JjL2xvZ2dlci50eXBlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRGVmYXVsdExldmVscyB9IGZyb20gXCIuL3R5cGVzLmpzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmFzZUxvZ2dlciB7XG5cdGdldCBjdXJyZW50TGV2ZWwoKTogc3RyaW5nO1xuXHRnZXQgbG9nTGV2ZWxzKCk6IFJlY29yZDxzdHJpbmcsIG51bWJlcj47XG59XG5cbmV4cG9ydCB0eXBlIExvZ0ZuID0gKG1zZzogc3RyaW5nIHwgbnVtYmVyIHwgb2JqZWN0LCAuLi5hcmdzOiB1bmtub3duW10pID0+IHZvaWQ7XG5cbmV4cG9ydCB0eXBlIExvZ2dlcjxcblx0Q3VzdG9tTGV2ZWxzIGV4dGVuZHMgc3RyaW5nID0gbmV2ZXIsXG5cdEN1c3RvbU9ubHkgZXh0ZW5kcyB0cnVlIHwgZmFsc2UgPSB1bmRlZmluZWQsXG4+ID0ge1xuXHRbSyBpbiBEZWZhdWx0TGV2ZWxzIGFzIEN1c3RvbU9ubHkgZXh0ZW5kcyBmYWxzZSA/IEsgOiBuZXZlcl06IExvZ0ZuO1xufSAmIHtcblx0W1Byb3BlcnR5IGluIEN1c3RvbUxldmVsc106IExvZ0ZuO1xufSAmIHtcblx0aXNMZXZlbEVuYWJsZWQobGV2ZWw6IHN0cmluZyk6IGJvb2xlYW47XG59ICYgQmFzZUxvZ2dlcjtcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFTQSxXQVNlIn0=
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { DefaultCensor, DefaultRedactions } from "./types.js";
|
|
2
|
+
function keysFromPaths(paths) {
|
|
3
|
+
const keys = new Set();
|
|
4
|
+
for (const path of paths){
|
|
5
|
+
const segments = path.split(".").filter((segment)=>segment.length > 0 && segment !== "*");
|
|
6
|
+
const key = segments.at(-1);
|
|
7
|
+
if (key != null) {
|
|
8
|
+
keys.add(key);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return keys;
|
|
12
|
+
}
|
|
13
|
+
function isPlainObject(value) {
|
|
14
|
+
if (value == null || typeof value !== "object" || Array.isArray(value) || value instanceof Error) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const proto = Object.getPrototypeOf(value);
|
|
18
|
+
return proto === Object.prototype || proto === null;
|
|
19
|
+
}
|
|
20
|
+
function object(value, keys, censor = DefaultCensor, copies = new WeakMap()) {
|
|
21
|
+
if (value == null || typeof value !== "object") {
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
if (value instanceof Error) {
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
// A cycle in the input stays a cycle in the copy.
|
|
28
|
+
const copied = copies.get(value);
|
|
29
|
+
if (copied !== undefined) {
|
|
30
|
+
return copied;
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
const out = [];
|
|
34
|
+
copies.set(value, out);
|
|
35
|
+
for (const item of value){
|
|
36
|
+
out.push(object(item, keys, censor, copies));
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
if (!isPlainObject(value)) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
const out = {};
|
|
44
|
+
copies.set(value, out);
|
|
45
|
+
for (const [key, nested] of Object.entries(value)){
|
|
46
|
+
out[key] = keys.has(key) ? censor : object(nested, keys, censor, copies);
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
function fromOptions(options) {
|
|
51
|
+
return keysFromPaths(options?.paths ?? DefaultRedactions.paths);
|
|
52
|
+
}
|
|
53
|
+
export const redact = {
|
|
54
|
+
object,
|
|
55
|
+
keysFromPaths,
|
|
56
|
+
fromOptions
|
|
57
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LogEntryAdapter } from "../log-entry.adapter.js";
|
|
2
|
+
/**
|
|
3
|
+
* Test double: keeps every entry that passes the level threshold, prints
|
|
4
|
+
* nothing. `scribe.configure({ adapter: capture })`, run the code, then assert
|
|
5
|
+
* on `capture.entries`.
|
|
6
|
+
*/ export class CaptureAdapter extends LogEntryAdapter {
|
|
7
|
+
entries = [];
|
|
8
|
+
/** Entries at `level`. */ at(level) {
|
|
9
|
+
return this.entries.filter((entry)=>entry.level === level);
|
|
10
|
+
}
|
|
11
|
+
clear() {
|
|
12
|
+
this.entries.length = 0;
|
|
13
|
+
}
|
|
14
|
+
write(entry) {
|
|
15
|
+
this.entries.push(entry);
|
|
16
|
+
}
|
|
17
|
+
}
|
package/es6/src/testing/index.js
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjcmliZS9zY3JpYmUvc3JjL3Rlc3RpbmcvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHt9O1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFdBQVUifQ==
|
|
1
|
+
export * from "./capture.adapter.js";
|