Skip to content

Commit fb88613

Browse files
committed
perf(core): avoid cloning unchanged log fields
1 parent 04baadc commit fb88613

2 files changed

Lines changed: 50 additions & 16 deletions

File tree

packages/core/src/logger.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -322,33 +322,44 @@ function filterKeys(obj: unknown, keys: Set<string>, depth = 0): any {
322322

323323
if (Array.isArray(obj)) {
324324
const isTruncated = obj.length > MAX_ARRAY_LENGTH;
325-
const items = (isTruncated ? obj.slice(0, MAX_ARRAY_LENGTH) : obj).map((item) =>
326-
filterKeys(item, keys, depth + 1)
327-
);
325+
const length = isTruncated ? MAX_ARRAY_LENGTH : obj.length;
326+
let filteredItems: unknown[] | undefined = isTruncated ? [] : undefined;
327+
328+
for (let index = 0; index < length; index++) {
329+
const item = obj[index];
330+
const filteredItem = filterKeys(item, keys, depth + 1);
331+
332+
if (filteredItems) {
333+
filteredItems.push(filteredItem);
334+
} else if (filteredItem !== item) {
335+
filteredItems = obj.slice(0, index);
336+
filteredItems.push(filteredItem);
337+
}
338+
}
328339

329340
if (isTruncated) {
330-
items.push(`[truncated ${obj.length - MAX_ARRAY_LENGTH} more items]`);
341+
filteredItems!.push(`[truncated ${obj.length - MAX_ARRAY_LENGTH} more items]`);
331342
}
332343

333-
return items;
344+
return filteredItems ?? obj;
334345
}
335346

336-
const filteredObj: any = {};
347+
let filteredObj: Record<string, unknown> | undefined;
337348

338349
for (const [key, value] of Object.entries(obj)) {
339-
if (keys.has(key.toLowerCase())) {
340-
if (value) {
341-
filteredObj[key] = `[filtered ${prettyPrintBytes(value)}]`;
342-
} else {
343-
filteredObj[key] = value;
344-
}
345-
continue;
350+
const filteredValue = keys.has(key.toLowerCase())
351+
? value
352+
? `[filtered ${prettyPrintBytes(value)}]`
353+
: value
354+
: filterKeys(value, keys, depth + 1);
355+
356+
if (filteredValue !== value) {
357+
filteredObj ??= { ...(obj as Record<string, unknown>) };
358+
filteredObj[key] = filteredValue;
346359
}
347-
348-
filteredObj[key] = filterKeys(value, keys, depth + 1);
349360
}
350361

351-
return filteredObj;
362+
return filteredObj ?? obj;
352363
}
353364

354365
function truncateString(value: string): string {

packages/core/test/logger.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,27 @@ describe("redact()", () => {
208208

209209
expect(result.connectionString).toMatch(/^\[filtered/);
210210
});
211+
212+
it("preserves references when no values need redaction or truncation", () => {
213+
const nested = { keep: "this stays" };
214+
const value = { nested, values: ["one", "two"] };
215+
216+
const result = redact(value);
217+
218+
expect(result).toBe(value);
219+
expect((result as typeof value).nested).toBe(nested);
220+
expect((result as typeof value).values).toBe(value.values);
221+
});
222+
223+
it("returns a redacted copy without mutating the input", () => {
224+
const nested = { token: "secret" };
225+
const value = { nested };
226+
227+
const result = redact(value) as typeof value;
228+
229+
expect(result).not.toBe(value);
230+
expect(result.nested).not.toBe(nested);
231+
expect(result.nested.token).toMatch(/^\[filtered/);
232+
expect(nested.token).toBe("secret");
233+
});
211234
});

0 commit comments

Comments
 (0)