Skip to content

feat(library-config)!: caller-supplied threadlocal schema and extra process-context attributes#2162

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 10 commits into
mainfrom
szegedi/threadlocal-schema-and-extras
Jul 1, 2026
Merged

feat(library-config)!: caller-supplied threadlocal schema and extra process-context attributes#2162
gh-worker-dd-mergequeue-cf854d[bot] merged 10 commits into
mainfrom
szegedi/threadlocal-schema-and-extras

Conversation

@szegedi

@szegedi szegedi commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

TracerMetadata::to_otel_process_ctx used to hardcode threadlocal.schema_version = "tlsdesc_v1_dev" and offered no way to publish additional threadlocal.* attributes. A language-specific writer (e.g. a Node.js writer with its own V8 layout constants under a different schema) couldn't fully drive the process context through this path.

This PR introduces a ThreadLocalMetadata substruct that gathers all thread-local context configuration in one place, and replaces the existing threadlocal_attribute_keys field on TracerMetadata with a single Option<ThreadLocalMetadata> threadlocal_metadata:

#[cfg(feature = "otel-thread-ctx")]
pub struct ThreadLocalMetadata {
    pub attribute_keys: Vec<String>,
    pub schema_version: Option<String>,
    pub extra_attributes: Vec<(String, any_value::Value)>,
}
  • attribute_keys — same role as the previous threadlocal_attribute_keys. The first key is still implicitly datadog.local_root_span_id.
  • schema_version — value of threadlocal.schema_version published in the process context. Falls back to "tlsdesc_v1_dev" when None, preserving the behavior current callers rely on.
  • extra_attributes — additional KeyValues to publish in the process context, e.g. the V8 threadlocal.wrapped_object_offset / threadlocal.tagged_size layout constants the Node.js reader needs. Values are typed directly as any_value::Value, so callers can use any of the OTel-supported variants (string, int, bool, double, bytes, array, kvlist).

Option<ThreadLocalMetadata> is the single switch for whether the threadlocal.* section appears at all. Illegal states like "schema_version set but no key map" are unrepresentable by construction.

Backward compatibility

Adding fields to ThreadLocalMetadata (rather than directly to TracerMetadata) means future extensions don't break exhaustive struct literals at call sites. Existing threadlocal_attribute_keys: Some(vec![...]) callers migrate to threadlocal_metadata: Some(ThreadLocalMetadata { attribute_keys: vec![...], ..Default::default() }) — that's a breaking change, hence the ! in the PR title, but in practice the only in-tree consumer is libdatadog-nodejs.

Also dropped Eq, Hash from TracerMetadata's derive: any_value::Value contains f64 (no Eq/Hash) and arrays (no Hash). Nothing in-tree puts TracerMetadata in a hash-keyed collection; PartialEq is retained.

Test plan

  • cargo test -p libdd-library-config --features otel-thread-ctx
  • Wire up ThreadLocalMetadata in libdatadog-nodejs's process_discovery crate
  • Have dd-trace-js pass schema "nodejs_v1_dev" + V8 layout constants through, dropping its own ad-hoc handling

Jira: PROF-15221

@datadog-prod-us1-4

datadog-prod-us1-4 Bot commented Jun 25, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 74.29% (-0.02%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 0d0b4d7 | Docs | Datadog PR Page | Give us feedback!

@github-actions

Copy link
Copy Markdown
Contributor

Clippy Allow Annotation Report

Comparing clippy allow annotations between branches:

  • Base Branch: origin/main
  • PR Branch: origin/szegedi/threadlocal-schema-and-extras

Summary by Rule

Rule Base Branch PR Branch Change

Annotation Counts by File

File Base Branch PR Branch Change

Annotation Stats by Crate

Crate Base Branch PR Branch Change
clippy-annotation-reporter 5 5 No change (0%)
datadog-ffe-ffi 1 1 No change (0%)
datadog-ipc 22 22 No change (0%)
datadog-live-debugger 4 4 No change (0%)
datadog-live-debugger-ffi 10 10 No change (0%)
datadog-profiling-replayer 4 4 No change (0%)
datadog-sidecar 45 45 No change (0%)
libdd-common 13 13 No change (0%)
libdd-common-ffi 12 12 No change (0%)
libdd-data-pipeline 6 6 No change (0%)
libdd-ddsketch 2 2 No change (0%)
libdd-dogstatsd-client 1 1 No change (0%)
libdd-profiling 13 13 No change (0%)
libdd-remote-config 3 3 No change (0%)
libdd-telemetry 20 20 No change (0%)
libdd-tinybytes 4 4 No change (0%)
libdd-trace-normalization 2 2 No change (0%)
libdd-trace-obfuscation 3 3 No change (0%)
libdd-trace-stats 1 1 No change (0%)
libdd-trace-utils 11 11 No change (0%)
Total 182 182 No change (0%)

About This Report

This report tracks Clippy allow annotations for specific rules, showing how they've changed in this PR. Decreasing the number of these annotations generally improves code quality.

@szegedi
szegedi force-pushed the szegedi/threadlocal-schema-and-extras branch from c22f97e to 9543321 Compare June 25, 2026 14:37
@szegedi szegedi changed the title Allow caller to override threadlocal schema and add extra process-context attributes feat(library-config)!: support caller-supplied threadlocal schema and extra process-context attributes Jun 25, 2026
@szegedi
szegedi force-pushed the szegedi/threadlocal-schema-and-extras branch from 9543321 to ce85ea7 Compare June 25, 2026 14:43
@szegedi szegedi changed the title feat(library-config)!: support caller-supplied threadlocal schema and extra process-context attributes feat(library-config)!: caller-supplied threadlocal schema and extra process-context attributes Jun 25, 2026
@szegedi
szegedi force-pushed the szegedi/threadlocal-schema-and-extras branch from ce85ea7 to 79d90e9 Compare June 25, 2026 14:52
@szegedi
szegedi marked this pull request as ready for review June 25, 2026 15:31
@szegedi
szegedi requested a review from a team as a code owner June 25, 2026 15:31
@szegedi
szegedi requested review from vpellan and removed request for a team June 25, 2026 15:31
@dd-octo-sts

dd-octo-sts Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Artifact Size Benchmark Report

aarch64-alpine-linux-musl
Artifact Baseline Commit Change
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.a 85.64 MB 85.64 MB +0% (+8 B) 👌
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 7.88 MB 7.88 MB 0% (0 B) 👌
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 96.81 MB 96.81 MB +0% (+8 B) 👌
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.60 MB 10.60 MB 0% (0 B) 👌
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 25.41 MB 25.41 MB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.lib 88.04 KB 88.04 KB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.pdb 184.50 MB 184.51 MB +0% (+8.00 KB) 👌
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 945.48 MB 945.48 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 8.29 MB 8.29 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.lib 88.04 KB 88.04 KB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.pdb 24.52 MB 24.52 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 48.85 MB 48.85 MB 0% (0 B) 👌
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 22.02 MB 22.02 MB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.lib 89.42 KB 89.42 KB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.pdb 188.51 MB 188.53 MB +0% (+16.00 KB) 👌
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 932.67 MB 932.67 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 6.41 MB 6.41 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.lib 89.42 KB 89.42 KB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.pdb 26.32 MB 26.32 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 46.48 MB 46.48 MB 0% (0 B) 👌
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 76.38 MB 76.38 MB 0% (0 B) 👌
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 8.76 MB 8.76 MB 0% (0 B) 👌
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 91.86 MB 91.86 MB 0% (0 B) 👌
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.66 MB 10.66 MB 0% (0 B) 👌

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79d90e9755

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@@ -132,7 +171,9 @@ impl TracerMetadata {
if let Some(threadlocal_attribute_keys) = threadlocal_attribute_keys.as_ref() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Emit supplied threadlocal extras without requiring a key map

When a caller sets threadlocal_schema_version or threadlocal_extra_attributes but has no additional attribute keys to publish, this guard skips the whole block and silently drops the supplied schema/layout attributes. That prevents the new caller-supplied process-context fields from working unless callers also know to set threadlocal_attribute_keys to Some(vec![]), even when they do not need a key map; gate the schema, key map, and extras independently so provided extras are actually published.

Useful? React with 👍 / 👎.

@yannham yannham left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The motivation LGTM. I wonder though if we shouldn't gather all thread-locals related stuff in a substruct, something like:

#[cfg(feature = "otel-thread-ctx")]
ThreadLocalMetadata {
        threadlocal_attribute_keys: Vec<String>,
        threadlocal_schema_version: Option<String>,
        threadlocal_extra_attributes: Vec<(String, ProcessContextAttrValue)>,
}

And then have in TracerMetadata a single field

    #[cfg(feature = "otel-thread-ctx")]
    #[serde(skip)]
    pub threadlocal_metadata: Option<ThreadLocalMetadata>,

The idea being that this avoid illegal states that are currently possible, like threadlocal_extra_attributes or threadlocal_schema_version being defined/non-empty but with attribute_keys being empty, which results in silently not publishing a ProcessContext.

With the ThreadLocalMetadata, the single point of activation is whether threadlocal_metadata is Some or not. So it's not possible to have it halfway defined.

This would be breaking but is ok - in practice the FFI is the only one currently using this code, so it's all within libdatadog, to the best of my knowledge.

What do you think?

/// Value of an additional OTel process-context attribute. Mirrors the small subset of
/// `opentelemetry::proto::common::v1::AnyValue` variants we support for caller-supplied threadlocal
/// extras — string and 64-bit integer, since the only consumers so far are textual schema
/// identifiers and small numeric layout constants (e.g. struct offsets, pointer widths).

@yannham yannham Jun 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we confident this will always be the case? I feel a simple approach would just to let caller set any value supported by the process context spec (and that would get rid of this additional type). Put differently, would that be a problem / redflag if libdatadog consumers passed something else than a string or an int?

It's ok to start like this and evolve in the future (although it's a breaking change), we don't have to envision all possible use cases right now. I'm asking mostly because it adds boilerplate, so wondering if it's really necessary.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, we can either go with Vec<(String, any_value::Value)> or even Vec<KeyValue> in which case the caller needs to construct KeyValue. For that reason, I'd lean towards Vec(String, any_value::Value) although admittedly I don't have enough idiomatic Rust experience to decide. Which one would you suggest?

Comment thread libdd-library-config/src/tracer_metadata.rs Outdated
Comment thread libdd-library-config/src/tracer_metadata.rs Outdated
@yannham

yannham commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

(Another solution would be to remove the Option around attribute_keys and just publish a context unconditionally)

@szegedi

szegedi commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

@yannham I like the suggestion of adding a struct a lot, I'm all for eliminating illegal states. I might remove the threadlocal_ prefix from its fields though, although that's admittedly a bikeshedding:

#[cfg(feature = "otel-thread-ctx")]
ThreadLocalMetadata {
        attribute_keys: Vec<String>,
        schema_version: Option<String>,
        extra_attributes: Vec<(String, ProcessContextAttrValue)>,
}

@szegedi
szegedi force-pushed the szegedi/threadlocal-schema-and-extras branch 3 times, most recently from 261edb3 to 6e826b1 Compare June 26, 2026 11:01
@szegedi

szegedi commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

I updated the PR with the suggestions.

For one, switched to any_value::Value for extra attributes. It does have one weird side effect, though: I had to drop Eq and Hash from TracerMetadata's derive (required since any_value::Value can also be f64 and arrays, and those don't have Eq and Hash either). No internal consumer puts TracerMetadata in a hash-keyed collection so I think this is fine? It retains PartialEq so existing equality test still works.

For another, I introduced the ThreadlocalMetadata struct; it's indeed much cleaner like this.

Apologies for force pushes after review; my clanker did that by amending into the original commit and force-pushing. I restored the original commit from reflog and then applied the changes on top again as separate commits, so even though it says a bunch of "force pushed" in the PR history, the first commit is again the exact same SHA that you originally reviewed.

@szegedi
szegedi requested a review from yannham June 26, 2026 12:26

@ivoanjo ivoanjo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 LGTM. I'll delegate to @yannham the "make it a really nice rust API" details, yet I think overall this looks good from my side.

Comment thread libdd-library-config/src/tracer_metadata.rs Outdated
szegedi and others added 7 commits July 1, 2026 10:00
…ributes

The OTel process-context block emitted by TracerMetadata::to_otel_process_ctx
used to hardcode 'threadlocal.schema_version' to 'tlsdesc_v1_dev' and offered
no way to add further threadlocal.* attributes. Language-specific writers
(e.g. a Node.js writer that publishes its own V8 layout constants under a
different schema name) couldn't fully drive the process context through
this path.

Add two new fields on TracerMetadata, gated on the otel-thread-ctx feature:

- threadlocal_schema_version: Option<String> — explicit override of the
  schema attribute. Falls back to 'tlsdesc_v1_dev' when None and
  threadlocal_attribute_keys is Some, preserving backward-compatible
  behavior for existing callers.

- threadlocal_extra_attributes: Vec<(String, ProcessContextAttrValue)> —
  additional KeyValues emitted in the process context. The value type is
  a small enum (String or Int) covering the cases needed for writer
  layout / runtime metadata.

Emission of each piece is now independent: the schema attribute, the
key map, and each extra are emitted iff their source field is set.
Per review feedback: dropping the ProcessContextAttrValue enum (String + Int) avoids the
"what about bool/double/array" extension problem and reuses the otel_proto type that's
already part of this file's surface. The struct also has to drop its Eq+Hash derive,
since any_value::Value contains f64 (no Eq) and arrays (no Hash); nothing in-tree uses
TracerMetadata as a hash-map key, and PartialEq is preserved.
Per review: a single Option<ThreadLocalMetadata> field on TracerMetadata replaces the
three loose threadlocal_* fields. The 'illegal state' of schema/extras set without a key
map is now unrepresentable by construction. Field names inside the substruct drop the
threadlocal_ prefix since the namespace lives in the type name.
Co-authored-by: Yann Hamdaoui <[email protected]>
The applied review suggestion left a closure block-body brace unclosed (the trailing
`}));` collapsed three closes into what should have been four). Restructure the
.map(|...| KeyValue {...}) into expression form so there's no closure body to
close at all.
@szegedi
szegedi force-pushed the szegedi/threadlocal-schema-and-extras branch from 3fa7402 to e2d2ed3 Compare July 1, 2026 08:02
szegedi and others added 3 commits July 1, 2026 10:36
#2167 moved the threadlocal.* attributes from Resource.attributes into
ProcessContext.extra_attributes and renamed the test helper from
find_attr to find_extra_attr. Our tests, added before that fix landed,
still used the old name and lookup surface. Rename to match.
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot merged commit 7cdeb78 into main Jul 1, 2026
110 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot deleted the szegedi/threadlocal-schema-and-extras branch July 1, 2026 11:08
iunanua added a commit that referenced this pull request Jul 7, 2026
…ibdd-data-pipeline, libdd-li... (#2201)

# Release proposal for libdd-capabilities-impl, libdd-common,
libdd-data-pipeline, libdd-library-config, libdd-remote-config,
libdd-sampling, libdd-telemetry, libdd-tinybytes, libdd-trace-utils and
their dependencies

This PR contains version bumps based on public API changes and commits
since last release.

## libdd-capabilities
**Next version:** `2.1.0`
**Semver bump:** `minor`
**Tag:** `libdd-capabilities-v2.1.0`

### Commits

- feat(data-pipeline)!: add stdout log trace exporter (#2074)

## libdd-common
**Next version:** `5.1.0`
**Semver bump:** `minor`
**Tag:** `libdd-common-v5.1.0`

### Commits

- refactor(clippy): prefer core and alloc imports (#2196)
- fix: update rustls-webpki to 0.103.13 (#2187)
- fix: update anyhow for unsoundness (#2186)
- feat(machine id): Add helpers in ddcommon to fetch the machine UUID l…
(#2163)

## libdd-ddsketch
**Next version:** `1.1.0`
**Semver bump:** `minor`
**Tag:** `libdd-ddsketch-v1.1.0`

### Commits

- feat(data-pipeline)!: export client-computed span stats as OTLP trace
metrics (#2067)
- test(ddsketch): add microbenchmarks for add/encode/collapse (#2125)

## libdd-trace-protobuf
**Next version:** `4.0.0`
**Semver bump:** `major`
**Tag:** `libdd-trace-protobuf-v4.0.0`

### Commits

- chore!: update protobufs to be in sync with datadog-agent (#2180)
- feat(stats)!: add whole key cardinality limit (#2158)
- feat(remote-config)!: use the proto file from the agent (#2165)
- feat(data-pipeline): OTLP HTTP/protobuf trace export (#2115)

## libdd-capabilities-impl
**Next version:** `3.0.0`
**Semver bump:** `major`
**Tag:** `libdd-capabilities-impl-v3.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.1.0 → ^5.1.0

### Commits

- feat(data-pipeline)!: add stdout log trace exporter (#2074)

## libdd-library-config
**Next version:** `3.0.0`
**Semver bump:** `major`
**Tag:** `libdd-library-config-v3.0.0`

### ⚠️ major bump forced due to:

- `libdd-trace-protobuf`: ^3.0.2 → ^4.0.0

### Commits

- refactor(clippy): prefer core and alloc imports (#2196)
- feat(library-config)!: caller-supplied threadlocal schema and extra
process-context attributes (#2162)
- fix(otel-thread-ctx): put the threadlocal attributes at the right
place in the context (#2167)

## libdd-remote-config
**Next version:** `2.0.0`
**Semver bump:** `major`
**Tag:** `libdd-remote-config-v2.0.0`

### ⚠️ major bump forced due to:

- `libdd-trace-protobuf`: ^3.0.2 → ^4.0.0

### Commits

- refactor(libdd-remote-config)!: hide Target inner properties so they
are not leaked (#2182)
- feat(remote-config)!: use the proto file from the agent (#2165)
- refactor(rc): reexport Endpoint and Tag common types (#2147)

## libdd-trace-normalization
**Next version:** `3.0.0`
**Semver bump:** `major`
**Tag:** `libdd-trace-normalization-v3.0.0`

### ⚠️ major bump forced due to:

- `libdd-trace-protobuf`: ^3.0.1 → ^4.0.0

### Commits

- feat(data-pipeline)!: CSS Trace Filters (#1985)

## libdd-shared-runtime
**Next version:** `2.0.0`
**Semver bump:** `major`
**Tag:** `libdd-shared-runtime-v2.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.1.0 → ^5.1.0

### Commits

- feat(shared-runtime)!: SharedRuntime Borrowed & Owned mode (#2061)
- feat(shared-runtime)!: use weak waker in trigger [APMSP-3371] (#2050)

## libdd-trace-utils
**Next version:** `9.0.0`
**Semver bump:** `major`
**Tag:** `libdd-trace-utils-v9.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.2.0 → ^5.1.0
- `libdd-trace-protobuf`: ^3.0.2 → ^4.0.0

### Commits

- ci(miri): skip slow miri tests (#2188)
- chore!: update protobufs to be in sync with datadog-agent (#2180)
- feat(data-pipeline): add agentless export (#2081)
- feat(data-pipeline)!: add stdout log trace exporter (#2074)
- feat(data-pipeline): OTLP HTTP/protobuf trace export (#2115)
- feat(otlp)!: Export OTLP spans with attribute-level OTel compatibility
(#2091)
- test(trace-utils): add V05 msgpack decode microbenchmark (#2127)
- feat(data-pipeline)!: export client-computed span stats as OTLP trace
metrics (#2067)
- test(trace-utils): add VecMap microbenchmarks (#2126)
- chore(stats)!: submit p0 telemetry in stats (#2130)
- refactor(change-buffer)!: replace slot index with span_id, fix segment
isolation (#2105)
- feat(data-pipeline)!: CSS Trace Filters (#1985)
- feat(trace-exporter): add v1 span and its encoder (#2039)
- fix(trace-utils): mark decoded span maps as deduped (#2110)
- feat(trace-utils)!: change buffer implementation (#2055)
- feat(native-spans)!: change buffer foundation (#2046)
- refactor(span)!: use VecMap for `meta`, `metrics` and `meta_struct`
for v04 spans (#2043)
- test: fix timeouts on heavily contended scenarios (#2093)

## libdd-telemetry
**Next version:** `6.0.0`
**Semver bump:** `major`
**Tag:** `libdd-telemetry-v6.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.2.0 → ^5.1.0
- `libdd-shared-runtime`: ^1.0.0 → ^2.0.0

### Commits

- ci(miri): skip slow miri tests (#2188)
- refactor(libdd-telemetry)!: avoid leaking libdd-common types in the
public API (#2152)
- feat(shared-runtime)!: SharedRuntime Borrowed & Owned mode (#2061)

## libdd-trace-obfuscation
**Next version:** `5.0.0`
**Semver bump:** `major`
**Tag:** `libdd-trace-obfuscation-v5.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.2.0 → ^5.1.0
- `libdd-trace-protobuf`: ^3.0.2 → ^4.0.0
- `libdd-trace-utils`: ^8.0.0 → ^9.0.0

### Commits

- refactor(clippy): prefer core and alloc imports (#2196)
- ci(miri): skip slow miri tests (#2188)
- fix: update anyhow for unsoundness (#2186)

## libdd-trace-stats
**Next version:** `6.0.0`
**Semver bump:** `major`
**Tag:** `libdd-trace-stats-v6.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.2.0 → ^5.1.0
- `libdd-shared-runtime`: ^1.0.0 → ^2.0.0
- `libdd-trace-protobuf`: ^3.0.2 → ^4.0.0
- `libdd-trace-utils`: ^8.0.0 → ^9.0.0

### Commits

- chore!: update protobufs to be in sync with datadog-agent (#2180)
- feat(stats)!: send telemetry for cardinality limits (#2159)
- feat(stats)!: add whole key cardinality limit (#2158)
- fix(trace-stats)!: add grpc_method to aggregation key (#2151)
- feat(shared-runtime)!: SharedRuntime Borrowed & Owned mode (#2061)
- feat(data-pipeline)!: export client-computed span stats as OTLP trace
metrics (#2067)
- refactor(span)!: use VecMap for `meta`, `metrics` and `meta_struct`
for v04 spans (#2043)

## libdd-data-pipeline
**Next version:** `7.0.0`
**Semver bump:** `major`
**Tag:** `libdd-data-pipeline-v7.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.2.0 → ^5.1.0
- `libdd-shared-runtime`: ^1.0.0 → ^2.0.0
- `libdd-telemetry`: ^5.0.1 → ^6.0.0
- `libdd-trace-protobuf`: ^3.0.2 → ^4.0.0
- `libdd-trace-stats`: ^5.0.0 → ^6.0.0
- `libdd-trace-utils`: ^8.0.0 → ^9.0.0

### Commits

- feat(trace_exporter): enable telemetry in stats exporter (#2160)
- refactor(libdd-telemetry)!: avoid leaking libdd-common types in the
public API (#2152)
- feat(stats): emit canonical gRPC status name for OTLP
rpc.response.status_code (#2183)
- feat(data-pipeline): add agentless export (#2081)
- feat(stats)!: send telemetry for cardinality limits (#2159)
- feat(stats)!: add whole key cardinality limit (#2158)
- fix(trace-stats)!: add grpc_method to aggregation key (#2151)
- feat(data-pipeline)!: add stdout log trace exporter (#2074)
- feat(shared-runtime)!: SharedRuntime Borrowed & Owned mode (#2061)
- feat(data-pipeline): OTLP HTTP/protobuf trace export (#2115)
- feat(otlp)!: Export OTLP spans with attribute-level OTel compatibility
(#2091)
- feat(data-pipeline)!: export client-computed span stats as OTLP trace
metrics (#2067)
- chore(stats)!: submit p0 telemetry in stats (#2130)
- feat(data-pipeline)!: CSS Trace Filters (#1985)
- feat(shared-runtime)!: use weak waker in trigger [APMSP-3371] (#2050)
- refactor(span)!: use VecMap for `meta`, `metrics` and `meta_struct`
for v04 spans (#2043)
- feat(stats)!: add endpoint gating to client-side stats [APMSP-3361]
(#2040)

## libdd-dogstatsd-client
**Next version:** `4.0.0`
**Semver bump:** `major`
**Tag:** `libdd-dogstatsd-client-v4.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.1.0 → ^5.1.0


## libdd-sampling
**Next version:** `5.0.0`
**Semver bump:** `major`
**Tag:** `libdd-sampling-v5.0.0`

### ⚠️ major bump forced due to:

- `libdd-common`: ^4.2.0 → ^5.1.0
- `libdd-trace-utils`: ^8.0.0 → ^9.0.0


[APMSP-3371]:
https://datadoghq.atlassian.net/browse/APMSP-3371?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: iunanua <[email protected]>
taegyunkim pushed a commit that referenced this pull request Jul 8, 2026
…rocess-context attributes (#2162)

## Summary

`TracerMetadata::to_otel_process_ctx` used to hardcode `threadlocal.schema_version = "tlsdesc_v1_dev"` and offered no way to publish additional `threadlocal.*` attributes. A language-specific writer (e.g. a Node.js writer with its own V8 layout constants under a different schema) couldn't fully drive the process context through this path.

This PR introduces a `ThreadLocalMetadata` substruct that gathers all thread-local context configuration in one place, and replaces the existing `threadlocal_attribute_keys` field on `TracerMetadata` with a single `Option<ThreadLocalMetadata> threadlocal_metadata`:

```rust
#[cfg(feature = "otel-thread-ctx")]
pub struct ThreadLocalMetadata {
    pub attribute_keys: Vec<String>,
    pub schema_version: Option<String>,
    pub extra_attributes: Vec<(String, any_value::Value)>,
}
```

- **`attribute_keys`** — same role as the previous `threadlocal_attribute_keys`. The first key is still implicitly `datadog.local_root_span_id`.
- **`schema_version`** — value of `threadlocal.schema_version` published in the process context. Falls back to `"tlsdesc_v1_dev"` when `None`, preserving the behavior current callers rely on.
- **`extra_attributes`** — additional KeyValues to publish in the process context, e.g. the V8 `threadlocal.wrapped_object_offset` / `threadlocal.tagged_size` layout constants the Node.js reader needs. Values are typed directly as `any_value::Value`, so callers can use any of the OTel-supported variants (string, int, bool, double, bytes, array, kvlist).

`Option<ThreadLocalMetadata>` is the single switch for whether the `threadlocal.*` section appears at all. Illegal states like "schema_version set but no key map" are unrepresentable by construction.

## Backward compatibility

Adding fields to `ThreadLocalMetadata` (rather than directly to `TracerMetadata`) means future extensions don't break exhaustive struct literals at call sites. Existing `threadlocal_attribute_keys: Some(vec![...])` callers migrate to `threadlocal_metadata: Some(ThreadLocalMetadata { attribute_keys: vec![...], ..Default::default() })` — that's a breaking change, hence the `!` in the PR title, but in practice the only in-tree consumer is `libdatadog-nodejs`.

Also dropped `Eq, Hash` from `TracerMetadata`'s derive: `any_value::Value` contains `f64` (no `Eq`/`Hash`) and arrays (no `Hash`). Nothing in-tree puts `TracerMetadata` in a hash-keyed collection; `PartialEq` is retained.

## Test plan

- [x] `cargo test -p libdd-library-config --features otel-thread-ctx`
- [ ] Wire up `ThreadLocalMetadata` in `libdatadog-nodejs`'s `process_discovery` crate
- [ ] Have `dd-trace-js` pass schema `"nodejs_v1_dev"` + V8 layout constants through, dropping its own ad-hoc handling

Jira: [PROF-15221]

[PROF-15221]: https://datadoghq.atlassian.net/browse/PROF-15221?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

Co-authored-by: attila.szegedi <[email protected]>
Signed-off-by: Taegyun Kim <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants