Skip to content

Commit 6915d9e

Browse files
Fix: Handle circular references in flattenAttributes function
1 parent 1c80a74 commit 6915d9e

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

packages/core/src/v3/utils/flattenAttributes.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { Attributes } from "@opentelemetry/api";
22

33
export const NULL_SENTINEL = "$@null((";
4+
export const CIRCULAR_REFERENCE_SENTINEL = "$@circular((";
45

56
export function flattenAttributes(
67
obj: Record<string, unknown> | Array<unknown> | string | boolean | number | null | undefined,
7-
prefix?: string
8+
prefix?: string ,
9+
seen: WeakSet<object> = new WeakSet()
810
): Attributes {
911
const result: Attributes = {};
1012

@@ -38,13 +40,25 @@ export function flattenAttributes(
3840
return result;
3941
}
4042

43+
// Check for circular reference
44+
if (typeof obj === "object" && seen.has(obj)) {
45+
result[prefix || ""] = CIRCULAR_REFERENCE_SENTINEL;
46+
return result;
47+
}
48+
49+
// Add object to seen set
50+
if (typeof obj === "object") {
51+
seen.add(obj);
52+
}
53+
54+
4155
for (const [key, value] of Object.entries(obj)) {
4256
const newPrefix = `${prefix ? `${prefix}.` : ""}${Array.isArray(obj) ? `[${key}]` : key}`;
4357
if (Array.isArray(value)) {
4458
for (let i = 0; i < value.length; i++) {
4559
if (typeof value[i] === "object" && value[i] !== null) {
4660
// update null check here as well
47-
Object.assign(result, flattenAttributes(value[i], `${newPrefix}.[${i}]`));
61+
Object.assign(result, flattenAttributes(value[i], `${newPrefix}.[${i}]`,seen));
4862
} else {
4963
if (value[i] === null) {
5064
result[`${newPrefix}.[${i}]`] = NULL_SENTINEL;
@@ -55,7 +69,7 @@ export function flattenAttributes(
5569
}
5670
} else if (isRecord(value)) {
5771
// update null check here
58-
Object.assign(result, flattenAttributes(value, newPrefix));
72+
Object.assign(result, flattenAttributes(value, newPrefix, seen));
5973
} else {
6074
if (typeof value === "number" || typeof value === "string" || typeof value === "boolean") {
6175
result[newPrefix] = value;
@@ -125,7 +139,7 @@ export function unflattenAttributes(
125139
}
126140
const lastPart = parts[parts.length - 1];
127141
if (lastPart) {
128-
current[lastPart] = rehydrateNull(value);
142+
current[lastPart] = rehydrateNull(rehydrateCircular(value));
129143
}
130144
}
131145

@@ -142,6 +156,13 @@ export function unflattenAttributes(
142156
return result;
143157
}
144158

159+
function rehydrateCircular(value: any): any {
160+
if (value === CIRCULAR_REFERENCE_SENTINEL) {
161+
return "[Circular Reference]";
162+
}
163+
return value;
164+
}
165+
145166
export function primitiveValueOrflattenedAttributes(
146167
obj: Record<string, unknown> | Array<unknown> | string | boolean | number | undefined,
147168
prefix: string | undefined

0 commit comments

Comments
 (0)