From f8926deaf9d0c5c9a6aa5eec8782e3f9eec49133 Mon Sep 17 00:00:00 2001 From: Bryan English Date: Thu, 16 Jul 2026 10:20:55 -0400 Subject: [PATCH 1/2] fix(pipeline): refresh views after string interning grows memory String interning can grow WASM memory and detach existing DataViews while queueOp is assembling an operation. Refresh the change-buffer views after interning before writing the string id. --- test/pipeline.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/test/pipeline.js b/test/pipeline.js index bc6eabf..7dd7303 100644 --- a/test/pipeline.js +++ b/test/pipeline.js @@ -239,7 +239,7 @@ class NativeSpansInterface { this.cqbCount = 0 } - const view = this._cqbView + let view = this._cqbView // Op header: opcode (u16 LE) + span_id (u64 LE) = 10 bytes. Rust reads the // opcode as a u16, then the span_id as a u64. view.setUint16(this.cqbIndex, op, true) @@ -250,6 +250,10 @@ class NativeSpansInterface { for (const arg of args) { if (typeof arg === 'string') { const stringId = this.getStringId(arg) + if (this._wasmMemory.buffer !== view.buffer) { + this._refreshViews() + view = this._cqbView + } view.setUint32(this.cqbIndex, stringId, true) this.cqbIndex += 4 } else { @@ -743,6 +747,28 @@ describe('pipeline', { skip }, () => { assert.strictEqual(span.getTag('bulk-key'), 'bulk-val') }) + it('refreshes change-buffer views when string interning grows memory', () => { + const span = nativeSpans.createSpan() + const getStringId = nativeSpans.getStringId.bind(nativeSpans) + let grew = false + nativeSpans.getStringId = (str) => { + const id = getStringId(str) + if (!grew) { + grew = true + wasmMemory.grow(1) + } + return id + } + + try { + span.setTag('grow-key', 'grow-value') + + assert.strictEqual(span.getTag('grow-key'), 'grow-value') + } finally { + nativeSpans.getStringId = getStringId + } + }) + it('rejects a malformed (non-terminated) stringTableInsertMany entry', () => { const ptr = nativeSpans.state.string_table_input_ptr() const len = nativeSpans.state.string_table_input_len() From 42d3474c846f5060cc4ebc062d4e68d13b8456e2 Mon Sep 17 00:00:00 2001 From: Bryan English Date: Thu, 16 Jul 2026 11:42:23 -0400 Subject: [PATCH 2/2] v0.18.0 --- Cargo.lock | 27 ++++++++++++++------------- crates/capabilities/Cargo.toml | 2 +- crates/pipeline/Cargo.toml | 14 +++++++------- package.json | 2 +- test/pipeline.js | 7 +++++++ 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70471b0..d852cbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -858,7 +858,7 @@ dependencies = [ [[package]] name = "libdd-capabilities" version = "2.1.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "anyhow", "bytes", @@ -882,7 +882,7 @@ dependencies = [ [[package]] name = "libdd-capabilities-impl" version = "3.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "bytes", "http", @@ -929,7 +929,7 @@ dependencies = [ [[package]] name = "libdd-common" version = "5.1.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "anyhow", "bytes", @@ -992,7 +992,7 @@ dependencies = [ [[package]] name = "libdd-data-pipeline" version = "7.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "anyhow", "arc-swap", @@ -1034,7 +1034,7 @@ dependencies = [ [[package]] name = "libdd-ddsketch" version = "1.1.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "prost", ] @@ -1042,7 +1042,7 @@ dependencies = [ [[package]] name = "libdd-dogstatsd-client" version = "4.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "anyhow", "cadence", @@ -1114,7 +1114,7 @@ dependencies = [ [[package]] name = "libdd-shared-runtime" version = "2.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "async-trait", "futures", @@ -1158,7 +1158,7 @@ dependencies = [ [[package]] name = "libdd-tinybytes" version = "1.1.1" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "serde", ] @@ -1166,7 +1166,7 @@ dependencies = [ [[package]] name = "libdd-trace-normalization" version = "3.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "anyhow", "libdd-trace-protobuf 4.0.0", @@ -1175,7 +1175,7 @@ dependencies = [ [[package]] name = "libdd-trace-obfuscation" version = "5.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "anyhow", "fluent-uri", @@ -1201,7 +1201,7 @@ dependencies = [ [[package]] name = "libdd-trace-protobuf" version = "4.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "prost", "serde", @@ -1211,7 +1211,7 @@ dependencies = [ [[package]] name = "libdd-trace-stats" version = "6.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "anyhow", "arc-swap", @@ -1238,7 +1238,7 @@ dependencies = [ [[package]] name = "libdd-trace-utils" version = "9.0.0" -source = "git+https://github.com/DataDog/libdatadog.git?rev=8cd68ab922fb7aade0f089ccfc91291d874673af#8cd68ab922fb7aade0f089ccfc91291d874673af" +source = "git+https://github.com/DataDog/libdatadog.git?rev=6356aee4c69b51f27e7e82e43b1797f60b74905a#6356aee4c69b51f27e7e82e43b1797f60b74905a" dependencies = [ "anyhow", "base64", @@ -1250,6 +1250,7 @@ dependencies = [ "http-body", "http-body-util", "indexmap", + "itoa", "libdd-capabilities 2.1.0", "libdd-capabilities-impl 3.0.0", "libdd-common 5.1.0", diff --git a/crates/capabilities/Cargo.toml b/crates/capabilities/Cargo.toml index cbb376e..f468e7d 100644 --- a/crates/capabilities/Cargo.toml +++ b/crates/capabilities/Cargo.toml @@ -17,7 +17,7 @@ futures-core = "0.3" anyhow = "1" # TODO: Replace this temporary libdatadog PR rev with the official release/tag # that contains DataDog/libdatadog#2235, then regenerate Cargo.lock. -libdd-capabilities = { git = "https://github.com/DataDog/libdatadog.git", rev = "8cd68ab922fb7aade0f089ccfc91291d874673af" } +libdd-capabilities = { git = "https://github.com/DataDog/libdatadog.git", rev = "6356aee4c69b51f27e7e82e43b1797f60b74905a" } [dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/crates/pipeline/Cargo.toml b/crates/pipeline/Cargo.toml index f8e318a..c4440cf 100644 --- a/crates/pipeline/Cargo.toml +++ b/crates/pipeline/Cargo.toml @@ -16,13 +16,13 @@ serde_json = "1" libdatadog-nodejs-capabilities = { path = "../capabilities" } # TODO: Replace these temporary libdatadog PR revs with the official release/tag # that contains DataDog/libdatadog#2235, then regenerate Cargo.lock. -libdd-capabilities = { git = "https://github.com/DataDog/libdatadog.git", rev = "8cd68ab922fb7aade0f089ccfc91291d874673af" } -libdd-common = { git = "https://github.com/DataDog/libdatadog.git", rev = "8cd68ab922fb7aade0f089ccfc91291d874673af", default-features = false } -libdd-data-pipeline = { git = "https://github.com/DataDog/libdatadog.git", rev = "8cd68ab922fb7aade0f089ccfc91291d874673af", default-features = false } -libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog.git", rev = "8cd68ab922fb7aade0f089ccfc91291d874673af", default-features = false, features = ["change-buffer"] } -libdd-trace-stats = { git = "https://github.com/DataDog/libdatadog.git", rev = "8cd68ab922fb7aade0f089ccfc91291d874673af", default-features = false } -libdd-trace-protobuf = { git = "https://github.com/DataDog/libdatadog.git", rev = "8cd68ab922fb7aade0f089ccfc91291d874673af", default-features = false } -libdd-shared-runtime = { git = "https://github.com/DataDog/libdatadog.git", rev = "8cd68ab922fb7aade0f089ccfc91291d874673af", default-features = false } +libdd-capabilities = { git = "https://github.com/DataDog/libdatadog.git", rev = "6356aee4c69b51f27e7e82e43b1797f60b74905a" } +libdd-common = { git = "https://github.com/DataDog/libdatadog.git", rev = "6356aee4c69b51f27e7e82e43b1797f60b74905a", default-features = false } +libdd-data-pipeline = { git = "https://github.com/DataDog/libdatadog.git", rev = "6356aee4c69b51f27e7e82e43b1797f60b74905a", default-features = false } +libdd-trace-utils = { git = "https://github.com/DataDog/libdatadog.git", rev = "6356aee4c69b51f27e7e82e43b1797f60b74905a", default-features = false, features = ["change-buffer"] } +libdd-trace-stats = { git = "https://github.com/DataDog/libdatadog.git", rev = "6356aee4c69b51f27e7e82e43b1797f60b74905a", default-features = false } +libdd-trace-protobuf = { git = "https://github.com/DataDog/libdatadog.git", rev = "6356aee4c69b51f27e7e82e43b1797f60b74905a", default-features = false } +libdd-shared-runtime = { git = "https://github.com/DataDog/libdatadog.git", rev = "6356aee4c69b51f27e7e82e43b1797f60b74905a", default-features = false } rmp-serde = "1" bytes = "1" http = "1" diff --git a/package.json b/package.json index 50f90e4..77e1c68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@datadog/libdatadog", - "version": "0.17.0", + "version": "0.18.0", "description": "Node.js binding for libdatadog", "main": "index.js", "scripts": { diff --git a/test/pipeline.js b/test/pipeline.js index 7dd7303..15bbc79 100644 --- a/test/pipeline.js +++ b/test/pipeline.js @@ -970,6 +970,7 @@ describe('pipeline', { skip }, () => { method: req.method, url: req.url, ct: req.headers['content-type'], + clientComputedStats: req.headers['datadog-client-computed-stats'], len: Buffer.concat(chunks).length, body: Buffer.concat(chunks).toString(), }) @@ -982,6 +983,7 @@ describe('pipeline', { skip }, () => { const ns = new NativeSpansInterface({ agentUrl: `http://127.0.0.1:${port}`, tracerVersion: '7.0.0-pre', + clientComputedStats: true, }) ns.state.setOtlpEndpoint(`http://127.0.0.1:${port}/v1/traces`) const span = ns.createSpan() @@ -1001,6 +1003,11 @@ describe('pipeline', { skip }, () => { const body = JSON.parse(req.body) assert.strictEqual(body.resourceSpans[0].scopeSpans[0].scope.name, 'dd-trace-js') assert.strictEqual(body.resourceSpans[0].scopeSpans[0].scope.version, '7.0.0-pre') + assert.strictEqual(req.clientComputedStats, 'yes') + const resourceAttrs = body.resourceSpans[0].resource.attributes + assert.ok(resourceAttrs.some((attr) => { + return attr.key === '_dd.stats_computed' && attr.value.stringValue === 'true' + }), 'OTLP resource should mark client-computed stats') } finally { server.closeAllConnections?.() server.close()