-
Notifications
You must be signed in to change notification settings - Fork 176
Description
Discussed in #4718
Originally posted by yvele November 6, 2025
When logging an object that has multiple references to the same object (non-circular), it seems that the logger removes the duplicate reference entirely, even though it’s not circular.
cont ref = { name: "Bob" };
const obj = { ref1: ref, ref2: ref };
logger.info(obj);
// Output:
// {"ref1":{"name":"Bob"}}You can see that ref2, even though it’s not circular, is completely removed due to the implementation of circular reference removal.
This comes from the current implementation here:
powertools-lambda-typescript/packages/logger/src/Logger.ts
Lines 739 to 772 in b387db0
| /** | |
| * A custom JSON replacer function that is used to serialize the log items. | |
| * | |
| * By default, we already extend the default serialization behavior to handle `BigInt` and `Error` objects, as well as remove circular references. | |
| * When a custom JSON replacer function is passed to the Logger constructor, it will be called **before** our custom rules for each key-value pair in the object being stringified. | |
| * | |
| * This allows you to customize the serialization while still benefiting from the default behavior. | |
| * | |
| * @see {@link ConstructorOptions.jsonReplacerFn} | |
| */ | |
| protected getJsonReplacer(): (key: string, value: unknown) => void { | |
| const references = new WeakSet(); | |
| return (key, value) => { | |
| let replacedValue = value; | |
| if (this.#jsonReplacerFn) | |
| replacedValue = this.#jsonReplacerFn?.(key, replacedValue); | |
| if (replacedValue instanceof Error) { | |
| replacedValue = this.getLogFormatter().formatError(replacedValue); | |
| } | |
| if (typeof replacedValue === 'bigint') { | |
| return replacedValue.toString(); | |
| } | |
| if (typeof replacedValue === 'object' && replacedValue !== null) { | |
| if (references.has(replacedValue)) { | |
| return; | |
| } | |
| references.add(replacedValue); | |
| } | |
| return replacedValue; | |
| }; | |
| } |
I would expect both references (ref1 and ref2) to appear in the log output, since the structure is not circular, it’s just a shared reference.
If it’s intentional, could you explain the reasoning, e.g., is the goal to enforce unique object serialization or minimize payload size?
It might also be useful to add a unit test to explicitly cover this case (or document the current behavior) to make the intention clear for contributors.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status