@sockethub/logger 1.0.0-alpha.11 → 1.0.0-alpha.12
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/index.js +48 -4
- package/dist/index.js.map +3 -3
- package/package.json +2 -2
- package/src/index.test.ts +79 -0
- package/src/index.ts +39 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sockethub/logger",
|
|
3
3
|
"description": "Winston-based logger for Sockethub packages",
|
|
4
|
-
"version": "1.0.0-alpha.
|
|
4
|
+
"version": "1.0.0-alpha.12",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"author": "Nick Jennings <nick@silverbucket.net>",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/bun": "latest"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "f039dab3c3f67cbbf204476fc397532e973f82a8"
|
|
51
51
|
}
|
package/src/index.test.ts
CHANGED
|
@@ -176,6 +176,85 @@ describe("Logger Package", () => {
|
|
|
176
176
|
const log2 = createLogger("test:2");
|
|
177
177
|
expect(log2.transports.length).toBe(2);
|
|
178
178
|
});
|
|
179
|
+
|
|
180
|
+
it("serializes circular metadata with [Circular] marker in log output", () => {
|
|
181
|
+
const previousNodeEnv = process.env.NODE_ENV;
|
|
182
|
+
process.env.NODE_ENV = "production";
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
const log = createLogger("test:namespace");
|
|
186
|
+
const circular: { self?: unknown } = {};
|
|
187
|
+
circular.self = circular;
|
|
188
|
+
|
|
189
|
+
const consoleTransport = log.transports[0] as {
|
|
190
|
+
format: {
|
|
191
|
+
transform: (
|
|
192
|
+
info: Record<string, unknown>,
|
|
193
|
+
opts?: unknown,
|
|
194
|
+
) => Record<PropertyKey, unknown>;
|
|
195
|
+
options?: unknown;
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const transformed = consoleTransport.format.transform(
|
|
200
|
+
{
|
|
201
|
+
level: "info",
|
|
202
|
+
[Symbol.for("level")]: "info",
|
|
203
|
+
message: "circular metadata test",
|
|
204
|
+
namespace: "test:namespace",
|
|
205
|
+
circular,
|
|
206
|
+
},
|
|
207
|
+
consoleTransport.format.options,
|
|
208
|
+
);
|
|
209
|
+
const output = String(
|
|
210
|
+
transformed[Symbol.for("message")] ?? "",
|
|
211
|
+
).replace(/\u001b\[[0-9;]*m/g, "");
|
|
212
|
+
|
|
213
|
+
expect(output).toContain("circular metadata test");
|
|
214
|
+
expect(output).toContain("\"[Circular]\"");
|
|
215
|
+
} finally {
|
|
216
|
+
process.env.NODE_ENV = previousNodeEnv;
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("serializes Error metadata with name/message/stack in log output", () => {
|
|
221
|
+
const previousNodeEnv = process.env.NODE_ENV;
|
|
222
|
+
process.env.NODE_ENV = "production";
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const log = createLogger("test:namespace");
|
|
226
|
+
const consoleTransport = log.transports[0] as {
|
|
227
|
+
format: {
|
|
228
|
+
transform: (
|
|
229
|
+
info: Record<string, unknown>,
|
|
230
|
+
opts?: unknown,
|
|
231
|
+
) => Record<PropertyKey, unknown>;
|
|
232
|
+
options?: unknown;
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const transformed = consoleTransport.format.transform(
|
|
237
|
+
{
|
|
238
|
+
level: "error",
|
|
239
|
+
[Symbol.for("level")]: "error",
|
|
240
|
+
message: "error metadata test",
|
|
241
|
+
namespace: "test:namespace",
|
|
242
|
+
err: new Error("boom"),
|
|
243
|
+
},
|
|
244
|
+
consoleTransport.format.options,
|
|
245
|
+
);
|
|
246
|
+
const output = String(
|
|
247
|
+
transformed[Symbol.for("message")] ?? "",
|
|
248
|
+
).replace(/\u001b\[[0-9;]*m/g, "");
|
|
249
|
+
|
|
250
|
+
expect(output).toContain("error metadata test");
|
|
251
|
+
expect(output).toContain("\"name\":\"Error\"");
|
|
252
|
+
expect(output).toContain("\"message\":\"boom\"");
|
|
253
|
+
expect(output).toContain("\"stack\"");
|
|
254
|
+
} finally {
|
|
255
|
+
process.env.NODE_ENV = previousNodeEnv;
|
|
256
|
+
}
|
|
257
|
+
});
|
|
179
258
|
});
|
|
180
259
|
|
|
181
260
|
describe("logger context", () => {
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,43 @@ let hasLoggedInit = false;
|
|
|
16
16
|
let loggerContext = "";
|
|
17
17
|
let loggerNamespaceStore = new WeakMap<Logger, string>();
|
|
18
18
|
|
|
19
|
+
// Keep log formatting resilient when metadata contains errors, bigints, or cycles.
|
|
20
|
+
function safeStringify(value: unknown): string {
|
|
21
|
+
try {
|
|
22
|
+
const parents: object[] = [];
|
|
23
|
+
return JSON.stringify(value, function (_key, innerValue) {
|
|
24
|
+
if (innerValue instanceof Error) {
|
|
25
|
+
return {
|
|
26
|
+
name: innerValue.name,
|
|
27
|
+
message: innerValue.message,
|
|
28
|
+
stack: innerValue.stack,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (typeof innerValue === "bigint") {
|
|
32
|
+
return innerValue.toString();
|
|
33
|
+
}
|
|
34
|
+
if (typeof innerValue === "object" && innerValue !== null) {
|
|
35
|
+
// Only treat values on the current traversal path as circular.
|
|
36
|
+
// Shared references in sibling branches should serialize normally.
|
|
37
|
+
const parent = this as unknown;
|
|
38
|
+
while (
|
|
39
|
+
parents.length > 0 &&
|
|
40
|
+
parents[parents.length - 1] !== parent
|
|
41
|
+
) {
|
|
42
|
+
parents.pop();
|
|
43
|
+
}
|
|
44
|
+
if (parents.includes(innerValue)) {
|
|
45
|
+
return "[Circular]";
|
|
46
|
+
}
|
|
47
|
+
parents.push(innerValue);
|
|
48
|
+
}
|
|
49
|
+
return innerValue;
|
|
50
|
+
});
|
|
51
|
+
} catch {
|
|
52
|
+
return '"[Unserializable]"';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
19
56
|
/**
|
|
20
57
|
* Initialize the logger system with global configuration.
|
|
21
58
|
*
|
|
@@ -174,7 +211,7 @@ export function createLogger(
|
|
|
174
211
|
const ns = namespace ? `${namespace} ` : "";
|
|
175
212
|
const metaStr =
|
|
176
213
|
Object.keys(meta).length > 0
|
|
177
|
-
? ` ${
|
|
214
|
+
? ` ${safeStringify(meta)}`
|
|
178
215
|
: "";
|
|
179
216
|
return `${level}: ${ns}${message}${metaStr}`;
|
|
180
217
|
},
|
|
@@ -188,7 +225,7 @@ export function createLogger(
|
|
|
188
225
|
const ns = namespace ? `${namespace} ` : "";
|
|
189
226
|
const metaStr =
|
|
190
227
|
Object.keys(meta).length > 0
|
|
191
|
-
? ` ${
|
|
228
|
+
? ` ${safeStringify(meta)}`
|
|
192
229
|
: "";
|
|
193
230
|
return `${timestamp} ${level}: ${ns}${message}${metaStr}`;
|
|
194
231
|
},
|