From 45a180b9991306d5d3006db29c5ad3255231d593 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Sat, 21 Oct 2023 02:06:57 +0200 Subject: [PATCH] fix(core): serialize bigint in metadata to string (#619) * fix(core): serialize bigint in metadata to string * chore: extracted replacer into SegmentUtils * Update subsegment.d.ts Co-authored-by: Carol Abadeer <60774943+carolabadeer@users.noreply.github.com> * Update segment.d.ts Co-authored-by: Carol Abadeer <60774943+carolabadeer@users.noreply.github.com> --------- Co-authored-by: Andrea Amorosi Co-authored-by: Carol Abadeer <60774943+carolabadeer@users.noreply.github.com> --- .../core/lib/segments/attributes/subsegment.d.ts | 2 ++ .../core/lib/segments/attributes/subsegment.js | 14 ++++++++++++-- packages/core/lib/segments/segment.d.ts | 2 ++ packages/core/lib/segments/segment.js | 11 +++++++++-- packages/core/lib/segments/segment_utils.d.ts | 2 ++ packages/core/lib/segments/segment_utils.js | 8 ++++++++ .../unit/segments/attributes/subsegment.test.js | 6 ++++++ .../core/test/unit/segments/segment_utils.test.js | 10 ++++++++++ 8 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/core/lib/segments/attributes/subsegment.d.ts b/packages/core/lib/segments/attributes/subsegment.d.ts index 64db3433..b827e0ea 100644 --- a/packages/core/lib/segments/attributes/subsegment.d.ts +++ b/packages/core/lib/segments/attributes/subsegment.d.ts @@ -61,6 +61,8 @@ declare class Subsegment { toString(): string; toJSON(): { [key: string]: any }; + + serialize(subsegment?: Subsegment): string; } export = Subsegment; diff --git a/packages/core/lib/segments/attributes/subsegment.js b/packages/core/lib/segments/attributes/subsegment.js index a8644943..b46a52f6 100644 --- a/packages/core/lib/segments/attributes/subsegment.js +++ b/packages/core/lib/segments/attributes/subsegment.js @@ -401,7 +401,7 @@ Subsegment.prototype.format = function format() { this.trace_id = this.segment.trace_id; } - return JSON.stringify(this); + return this.serialize(); }; /** @@ -409,7 +409,7 @@ Subsegment.prototype.format = function format() { */ Subsegment.prototype.toString = function toString() { - return JSON.stringify(this); + return this.serialize(); }; Subsegment.prototype.toJSON = function toJSON() { @@ -428,4 +428,14 @@ Subsegment.prototype.toJSON = function toJSON() { return thisCopy; }; +/** + * Returns the serialized subsegment JSON string, replacing any BigInts with strings. + */ +Subsegment.prototype.serialize = function serialize(object) { + return JSON.stringify( + object ?? this, + SegmentUtils.getJsonStringifyReplacer() + ); +}; + module.exports = Subsegment; diff --git a/packages/core/lib/segments/segment.d.ts b/packages/core/lib/segments/segment.d.ts index 170b7f60..34de5974 100644 --- a/packages/core/lib/segments/segment.d.ts +++ b/packages/core/lib/segments/segment.d.ts @@ -64,6 +64,8 @@ declare class Segment { format(): string; toString(): string; + + serialize(segment?: Segment): string; } export = Segment; diff --git a/packages/core/lib/segments/segment.js b/packages/core/lib/segments/segment.js index 92aae521..b8f24533 100644 --- a/packages/core/lib/segments/segment.js +++ b/packages/core/lib/segments/segment.js @@ -431,11 +431,18 @@ Segment.prototype.format = function format() { false ); - return JSON.stringify(thisCopy); + return this.serialize(thisCopy); }; Segment.prototype.toString = function toString() { - return JSON.stringify(this); + return this.serialize(); +}; + +Segment.prototype.serialize = function serialize(object) { + return JSON.stringify( + object ?? this, + SegmentUtils.getJsonStringifyReplacer() + ); }; module.exports = Segment; diff --git a/packages/core/lib/segments/segment_utils.d.ts b/packages/core/lib/segments/segment_utils.d.ts index 197eb823..fd3a51f6 100644 --- a/packages/core/lib/segments/segment_utils.d.ts +++ b/packages/core/lib/segments/segment_utils.d.ts @@ -17,3 +17,5 @@ export function setStreamingThreshold(threshold: number): void; export function getStreamingThreshold(): number; export function getHttpResponseData(res: http.ServerResponse): object; + +export function getJsonStringifyReplacer(): (key: string, value: any) => any; diff --git a/packages/core/lib/segments/segment_utils.js b/packages/core/lib/segments/segment_utils.js index eb2cbb78..03514b68 100644 --- a/packages/core/lib/segments/segment_utils.js +++ b/packages/core/lib/segments/segment_utils.js @@ -67,6 +67,14 @@ var utils = { ret.content_length = safeParseInt(res.headers['content-length']); } return ret; + }, + + getJsonStringifyReplacer: () => (_, value) => { + if (typeof value === 'bigint') { + return value.toString(); + } + + return value; } }; diff --git a/packages/core/test/unit/segments/attributes/subsegment.test.js b/packages/core/test/unit/segments/attributes/subsegment.test.js index f68cbe85..ab7188bc 100644 --- a/packages/core/test/unit/segments/attributes/subsegment.test.js +++ b/packages/core/test/unit/segments/attributes/subsegment.test.js @@ -332,6 +332,12 @@ describe('Subsegment', function() { child.flush(); emitStub.should.have.been.called; }); + + it('should stringify bigint objects correctly', function() { + child.addMetadata('key', BigInt(9007199254740991)); + child.flush(); + emitStub.should.have.been.calledOnce; + }); }); describe('#streamSubsegments', function() { diff --git a/packages/core/test/unit/segments/segment_utils.test.js b/packages/core/test/unit/segments/segment_utils.test.js index fb0b747d..8b8cefff 100644 --- a/packages/core/test/unit/segments/segment_utils.test.js +++ b/packages/core/test/unit/segments/segment_utils.test.js @@ -43,4 +43,14 @@ describe('SegmentUtils', function() { assert.deepEqual(emptyRes, {}); }); }); + + describe('#getJsonStringifyReplacer', () => { + it('should stringify BigInts', () => { + const obj = {foo: 1n, bar: BigInt(2)}; + const replacer = SegmentUtils.getJsonStringifyReplacer(); + const result = JSON.stringify(obj, replacer); + + assert.equal(result, '{"foo":"1","bar":"2"}'); + }); + }); });