fix: preserve structured logger metadata

This commit is contained in:
MythEclipse
2026-05-19 02:43:52 +07:00
parent 1aa8c6a370
commit f8ba4b41e9
3 changed files with 45 additions and 17 deletions
+35 -16
View File
@@ -51,16 +51,33 @@ const serializeError = (error: Error): SerializedError => {
return serialized; return serialized;
}; };
const isPlainObject = (value: unknown): value is Record<string, unknown> => {
if (!value || typeof value !== "object") {
return false;
}
const prototype = Object.getPrototypeOf(value);
return prototype === Object.prototype || prototype === null;
};
const serializeLogValue = (value: unknown): unknown => { const serializeLogValue = (value: unknown): unknown => {
if (value instanceof Error) { if (value instanceof Error) {
return serializeError(value); return serializeError(value);
} }
if (value instanceof Date) {
return value.toISOString();
}
if (value instanceof RegExp) {
return value.toString();
}
if (Array.isArray(value)) { if (Array.isArray(value)) {
return value.map(serializeLogValue); return value.map(serializeLogValue);
} }
if (value && typeof value === "object") { if (isPlainObject(value)) {
return Object.fromEntries( return Object.fromEntries(
Object.entries(value).map(([key, nestedValue]) => [ Object.entries(value).map(([key, nestedValue]) => [
key, key,
@@ -79,13 +96,15 @@ const formatLogMetadata = (metadata: LogMetadata): LogMetadata => {
}; };
const metadataFormat = winston.format((info) => { const metadataFormat = winston.format((info) => {
const { level, message, timestamp, ...metadata } = info; const { level: _level, message: _message, timestamp: _timestamp, ...metadata } =
return { info;
level,
message, for (const key of Object.keys(metadata)) {
timestamp, delete info[key];
...formatLogMetadata(metadata), }
};
Object.assign(info, formatLogMetadata(metadata));
return info;
}); });
const consoleFormat = winston.format.printf((info) => { const consoleFormat = winston.format.printf((info) => {
@@ -142,15 +161,15 @@ const winstonLogger = winston.createLogger({
function wrapLogger(wLogger: winston.Logger): CustomLogger { function wrapLogger(wLogger: winston.Logger): CustomLogger {
const logAtLevel = (level: string) => { const logAtLevel = (level: string) => {
return (arg1: any, arg2?: any) => { return (arg1: any, arg2?: any) => {
if (typeof arg1 === "object" && arg1 !== null) { if (arg1 instanceof Error) {
// arg1 is object, arg2 is message string wLogger.log(level, arg1.message, { error: arg1 });
const msg = typeof arg2 === "string" ? arg2 : ""; } else if (typeof arg1 === "object" && arg1 !== null) {
wLogger.log(level, msg, { ...arg1 }); const message = typeof arg2 === "string" ? arg2 : "";
wLogger.log(level, message, { ...arg1 });
} else { } else {
// arg1 is message string, arg2 is metadata (or nothing) const message = typeof arg1 === "string" ? arg1 : String(arg1);
const msg = typeof arg1 === "string" ? arg1 : String(arg1); const metadata = typeof arg2 === "object" && arg2 !== null ? arg2 : {};
const meta = typeof arg2 === "object" && arg2 !== null ? arg2 : {}; wLogger.log(level, message, metadata);
wLogger.log(level, msg, meta);
} }
}; };
}; };
+1 -1
View File
@@ -32,7 +32,7 @@ export async function retryWithBackoff<T>(
{ {
attempt: error.attemptNumber, attempt: error.attemptNumber,
retriesLeft: error.retriesLeft, retriesLeft: error.retriesLeft,
error: error.error.message, error: error.error,
}, },
"Retry attempt", "Retry attempt",
); );
+9
View File
@@ -54,4 +54,13 @@ describe("logger serialization", () => {
formatLogMetadataForTest({ context: "bot", signal: "SIGINT", count: 2 }), formatLogMetadataForTest({ context: "bot", signal: "SIGINT", count: 2 }),
).toEqual({ context: "bot", signal: "SIGINT", count: 2 }); ).toEqual({ context: "bot", signal: "SIGINT", count: 2 });
}); });
it("serializes dates and regexps without dropping values", () => {
const createdAt = new Date("2026-05-19T00:00:00.000Z");
expect(formatLogMetadataForTest({ createdAt, pattern: /voice/i })).toEqual({
createdAt: "2026-05-19T00:00:00.000Z",
pattern: "/voice/i",
});
});
}); });