Skip to content

feat!: integrate obfuscation to trace exporter [APMSP-2764]#1819

Open
Eldolfin wants to merge 12 commits intomainfrom
oscarld/integrate-obfuscation-to-trace-exporter
Open

feat!: integrate obfuscation to trace exporter [APMSP-2764]#1819
Eldolfin wants to merge 12 commits intomainfrom
oscarld/integrate-obfuscation-to-trace-exporter

Conversation

@Eldolfin
Copy link
Copy Markdown
Contributor

@Eldolfin Eldolfin commented Mar 30, 2026

What does this PR do?

Integrate the work that has been done on obfuscate_span into the trace exporter

Motivation

Let the sdks obfuscate spans before sending them to the agent when possible, reducing the amount of data transfered from the sdks to the agent.

Additional Notes

Anything else we should know when reviewing?

How to test the change?

  • manual tests
  • system tests
  • unit tests

TODO

  • retrieve obfuscation config from /info
  • add a test for agent obfuscation version > library obfuscation version (it should not obfuscate)
  • obfuscate more than just sql and redis not for stats

@Eldolfin Eldolfin requested review from a team as code owners March 30, 2026 11:42
@Eldolfin Eldolfin changed the title wip: integrate obfuscation to trace exporter feat!: integrate obfuscation to trace exporter Mar 30, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 30, 2026

📚 Documentation Check Results

⚠️ 2095 documentation warning(s) found

📦 libdd-data-pipeline - 877 warning(s)

📦 libdd-trace-obfuscation - 649 warning(s)

📦 libdd-trace-stats - 569 warning(s)


Updated: 2026-04-13 14:07:53 UTC | Commit: af047bb | missing-docs job results

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 30, 2026

Clippy Allow Annotation Report

Comparing clippy allow annotations between branches:

  • Base Branch: origin/main
  • PR Branch: origin/oscarld/integrate-obfuscation-to-trace-exporter

Summary by Rule

Rule Base Branch PR Branch Change
unwrap_used 1 1 No change (0%)
Total 1 1 No change (0%)

Annotation Counts by File

File Base Branch PR Branch Change
libdd-data-pipeline/src/stats_exporter.rs 1 1 No change (0%)

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 21 21 No change (0%)
datadog-live-debugger 6 6 No change (0%)
datadog-live-debugger-ffi 10 10 No change (0%)
datadog-profiling-replayer 4 4 No change (0%)
datadog-remote-config 3 3 No change (0%)
datadog-sidecar 55 55 No change (0%)
libdd-common 10 10 No change (0%)
libdd-common-ffi 12 12 No change (0%)
libdd-data-pipeline 5 5 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-telemetry 19 19 No change (0%)
libdd-tinybytes 4 4 No change (0%)
libdd-trace-normalization 2 2 No change (0%)
libdd-trace-obfuscation 8 8 No change (0%)
libdd-trace-utils 15 15 No change (0%)
Total 196 196 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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 30, 2026

🔒 Cargo Deny Results

⚠️ 4 issue(s) found, showing only errors (advisories, bans, sources)

📦 libdd-data-pipeline - 2 error(s)

Show output
error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:208:1
    │
208 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
      
      Affected versions of `rand` are `>= 0.7, < 0.9.3` and `0.10.0`.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── libdd-common v3.0.2
      │   ├── libdd-capabilities-impl v0.1.0
      │   │   ├── (dev) libdd-data-pipeline v3.0.1
      │   │   └── (dev) libdd-trace-utils v3.0.1
      │   │       ├── libdd-data-pipeline v3.0.1 (*)
      │   │       ├── libdd-trace-stats v2.0.0
      │   │       │   └── libdd-data-pipeline v3.0.1 (*)
      │   │       └── (dev) libdd-trace-utils v3.0.1 (*)
      │   ├── libdd-data-pipeline v3.0.1 (*)
      │   ├── libdd-dogstatsd-client v2.0.0
      │   │   └── libdd-data-pipeline v3.0.1 (*)
      │   ├── libdd-shared-runtime v1.0.0
      │   │   ├── libdd-data-pipeline v3.0.1 (*)
      │   │   └── libdd-telemetry v4.0.0
      │   │       └── libdd-data-pipeline v3.0.1 (*)
      │   ├── libdd-telemetry v4.0.0 (*)
      │   └── libdd-trace-utils v3.0.1 (*)
      ├── (dev) libdd-data-pipeline v3.0.1 (*)
      ├── (dev) libdd-trace-normalization v2.0.0
      │   └── libdd-trace-utils v3.0.1 (*)
      ├── (dev) libdd-trace-stats v2.0.0 (*)
      ├── libdd-trace-utils v3.0.1 (*)
      └── proptest v1.5.0
          └── (dev) libdd-tinybytes v1.1.0
              ├── libdd-data-pipeline v3.0.1 (*)
              ├── (dev) libdd-tinybytes v1.1.0 (*)
              └── libdd-trace-utils v3.0.1 (*)

error[vulnerability]: Denial of Service via Stack Exhaustion
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:270:1
    │
270 │ time 0.3.41 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
    │
    ├ ID: RUSTSEC-2026-0009
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0009
    ├ ## Impact
      
      When user-provided input is provided to any type that parses with the RFC 2822 format, a denial of
      service attack via stack exhaustion is possible. The attack relies on formally deprecated and
      rarely-used features that are part of the RFC 2822 format used in a malicious manner. Ordinary,
      non-malicious input will never encounter this scenario.
      
      ## Patches
      
      A limit to the depth of recursion was added in v0.3.47. From this version, an error will be returned
      rather than exhausting the stack.
      
      ## Workarounds
      
      Limiting the length of user input is the simplest way to avoid stack exhaustion, as the amount of
      the stack consumed would be at most a factor of the length of the input.
    ├ Announcement: https://github.com/time-rs/time/blob/main/CHANGELOG.md#0347-2026-02-05
    ├ Solution: Upgrade to >=0.3.47 (try `cargo update -p time`)
    ├ time v0.3.41
      └── tracing-appender v0.2.3
          └── libdd-log v1.0.0
              └── (dev) libdd-data-pipeline v3.0.1

advisories FAILED, bans ok, sources ok

📦 libdd-trace-obfuscation - 1 error(s)

Show output
error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:182:1
    │
182 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
      
      Affected versions of `rand` are `>= 0.7, < 0.9.3` and `0.10.0`.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── (dev) libdd-common v3.0.2
      │   ├── libdd-capabilities-impl v0.1.0
      │   │   └── (dev) libdd-trace-utils v3.0.1
      │   │       ├── (dev) libdd-trace-obfuscation v2.0.0
      │   │       └── (dev) libdd-trace-utils v3.0.1 (*)
      │   ├── libdd-trace-obfuscation v2.0.0 (*)
      │   └── libdd-trace-utils v3.0.1 (*)
      ├── (dev) libdd-trace-normalization v2.0.0
      │   └── libdd-trace-utils v3.0.1 (*)
      ├── libdd-trace-utils v3.0.1 (*)
      └── proptest v1.5.0
          └── (dev) libdd-tinybytes v1.1.0
              ├── (dev) libdd-tinybytes v1.1.0 (*)
              └── libdd-trace-utils v3.0.1 (*)

advisories FAILED, bans ok, sources ok

📦 libdd-trace-stats - 1 error(s)

Show output
error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:182:1
    │
182 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by @lopopolo) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
      
      Affected versions of `rand` are `>= 0.7, < 0.9.3` and `0.10.0`.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 (try `cargo update -p rand`)
    ├ rand v0.8.5
      ├── (dev) libdd-common v3.0.2
      │   ├── libdd-capabilities-impl v0.1.0
      │   │   └── (dev) libdd-trace-utils v3.0.1
      │   │       ├── libdd-trace-stats v2.0.0
      │   │       └── (dev) libdd-trace-utils v3.0.1 (*)
      │   └── libdd-trace-utils v3.0.1 (*)
      ├── (dev) libdd-trace-normalization v2.0.0
      │   └── libdd-trace-utils v3.0.1 (*)
      ├── (dev) libdd-trace-stats v2.0.0 (*)
      ├── libdd-trace-utils v3.0.1 (*)
      └── proptest v1.5.0
          └── (dev) libdd-tinybytes v1.1.0
              ├── (dev) libdd-tinybytes v1.1.0 (*)
              └── libdd-trace-utils v3.0.1 (*)

advisories FAILED, bans ok, sources ok

Updated: 2026-04-13 14:08:04 UTC | Commit: af047bb | dependency-check job results

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Mar 30, 2026

Codecov Report

❌ Patch coverage is 60.82474% with 76 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.61%. Comparing base (d83038c) to head (50c0469).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1819      +/-   ##
==========================================
- Coverage   71.70%   71.61%   -0.09%     
==========================================
  Files         429      429              
  Lines       67916    68095     +179     
==========================================
+ Hits        48697    48767      +70     
- Misses      19219    19328     +109     
Components Coverage Δ
libdd-crashtracker 66.05% <ø> (+0.01%) ⬆️
libdd-crashtracker-ffi 34.47% <ø> (ø)
libdd-alloc 98.77% <ø> (ø)
libdd-data-pipeline 85.17% <46.85%> (-0.98%) ⬇️
libdd-data-pipeline-ffi 73.28% <ø> (+0.78%) ⬆️
libdd-common 79.16% <ø> (ø)
libdd-common-ffi 73.87% <ø> (ø)
libdd-telemetry 65.98% <ø> (ø)
libdd-telemetry-ffi 16.75% <ø> (ø)
libdd-dogstatsd-client 82.64% <ø> (ø)
datadog-ipc 73.10% <ø> (ø)
libdd-profiling 81.61% <ø> (-0.02%) ⬇️
libdd-profiling-ffi 64.94% <ø> (ø)
datadog-sidecar 30.07% <ø> (-0.47%) ⬇️
datdog-sidecar-ffi 6.59% <ø> (-2.18%) ⬇️
spawn-worker 54.69% <ø> (ø)
libdd-tinybytes 93.16% <ø> (ø)
libdd-trace-normalization 81.71% <ø> (ø)
libdd-trace-obfuscation 87.38% <100.00%> (+0.13%) ⬆️
libdd-trace-protobuf 68.25% <ø> (ø)
libdd-trace-utils 88.72% <ø> (ø)
datadog-tracer-flare 86.88% <ø> (ø)
libdd-log 74.69% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@datadog-datadog-prod-us1-2
Copy link
Copy Markdown

datadog-datadog-prod-us1-2 bot commented Mar 30, 2026

✅ Tests

🎉 All green!

❄️ No new flaky tests detected
🧪 All tests passed

🎯 Code Coverage (details)
Patch Coverage: 60.82%
Overall Coverage: 71.62% (-0.09%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 50c0469 | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback!

@Eldolfin Eldolfin marked this pull request as draft March 30, 2026 12:40
@Eldolfin Eldolfin requested a review from Copilot March 31, 2026 11:48
@Eldolfin
Copy link
Copy Markdown
Contributor Author

@codex review

@dd-octo-sts
Copy link
Copy Markdown
Contributor

dd-octo-sts bot commented Mar 31, 2026

Artifact Size Benchmark Report

aarch64-alpine-linux-musl
Artifact Baseline Commit Change
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.a 83.25 MB 83.33 MB +.09% (+83.20 KB) 🔍
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 7.63 MB 7.63 MB 0% (0 B) 👌
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.10 MB 10.10 MB +.04% (+4.58 KB) 🔍
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 99.29 MB 99.39 MB +.09% (+96.58 KB) 🔍
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 25.16 MB 25.20 MB +.19% (+50.50 KB) 🔍
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.lib 78.21 KB 78.21 KB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.pdb 184.22 MB 184.51 MB +.15% (+296.00 KB) 🔍
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 916.99 MB 917.99 MB +.10% (+1.00 MB) 🔍
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 7.88 MB 7.89 MB +.13% (+10.50 KB) 🔍
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.lib 78.21 KB 78.21 KB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.pdb 23.64 MB 23.67 MB +.13% (+32.00 KB) 🔍
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 46.13 MB 46.18 MB +.12% (+58.48 KB) 🔍
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 21.63 MB 21.68 MB +.20% (+45.50 KB) 🔍
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.lib 79.42 KB 79.42 KB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.pdb 188.31 MB 188.62 MB +.16% (+312.00 KB) 🔍
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 902.01 MB 903.01 MB +.11% (+1018.24 KB) 🔍
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 6.12 MB 6.13 MB +.14% (+9.00 KB) 🔍
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.lib 79.42 KB 79.42 KB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.pdb 25.31 MB 25.35 MB +.15% (+40.00 KB) 🔍
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 43.60 MB 43.66 MB +.12% (+56.30 KB) 🔍
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 74.38 MB 74.45 MB +.10% (+76.81 KB) 🔍
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 8.51 MB 8.52 MB +.13% (+12.00 KB) 🔍
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 91.66 MB 91.75 MB +.09% (+88.55 KB) 🔍
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.18 MB 10.19 MB +.10% (+11.21 KB) 🔍

Copy link
Copy Markdown

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

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: f2621f3041

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +228 to +232
client_side_stats.store(Arc::new(StatsComputationStatus::Enabled {
stats_concentrator: stats_concentrator.clone(),
cancellation_token: cancellation_token.clone(),
obfuscation_active: new_obfuscation_active,
}));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Recreate stats worker when obfuscation mode flips

When /info changes obfuscation support, this branch only updates client_side_stats and leaves the running StatsExporter untouched. The exporter’s obfuscation_active flag is fixed at construction time in create_and_start_stats_worker, so it keeps sending the old datadog-obfuscation-version header state even after process_traces_for_stats switches to the new obfuscation behavior. In the toggle scenario (e.g., agent enables obfuscation after startup), stats payload resources and header version can diverge, which makes the agent interpret stats under the wrong format/version.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR integrates obfuscation support into the trace exporter for client-side stats computation. It enables SDKs to obfuscate spans before sending them to the agent when the agent supports it, reducing data transfer between SDKs and the agent.

Changes:

  • Adds obfuscate_resource_for_stats function to obfuscate resource names for SQL, Redis, Cassandra, and Valkey spans
  • Implements obfuscation state tracking through the stats computation lifecycle
  • Creates an ObfuscatedStatSpan wrapper to provide obfuscated resources to the stats concentrator without modifying original spans
  • Adds HTTP header datadog-obfuscation-version: 1 when obfuscation is active
  • Adds schema field for agent's obfuscation version support
  • Fixes a typo in documentation ("will" → "while")

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
libdd-trace-stats/src/span_concentrator/mod.rs Exports the stat_span module publicly for use in the stats exporter
libdd-trace-obfuscation/src/obfuscate.rs Adds obfuscate_resource_for_stats function with comprehensive tests for SQL, Redis, Cassandra, and Valkey obfuscation
libdd-data-pipeline/src/trace_exporter/stats.rs Implements obfuscation state management and applies obfuscation to spans during stats computation
libdd-data-pipeline/src/trace_exporter/mod.rs Passes obfuscation state through the stats handler call chain
libdd-data-pipeline/src/stats_exporter.rs Adds obfuscation header to HTTP requests when obfuscation is active, includes test coverage
libdd-data-pipeline/src/agent_info/schema.rs Adds obfuscation_version field to capture agent capabilities
libdd-data-pipeline/Cargo.toml Adds dependency on libdd-trace-obfuscation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Eldolfin Eldolfin changed the title feat!: integrate obfuscation to trace exporter feat!: integrate obfuscation to trace exporter [APMSP-2764] Apr 3, 2026
@Eldolfin Eldolfin marked this pull request as ready for review April 13, 2026 14:27
gh-worker-dd-mergequeue-cf854d bot pushed a commit to DataDog/datadog-agent that referenced this pull request Apr 13, 2026
This config field is needed for CSS obfuscation. In fact this is the only needed obfuscation config field AFAIK.

### What does this PR do?
- adds a "sql_obfuscation_mode" field to /info endpoint for using it when obfuscating stats in libraries.

### Motivation
- finish [integrating obfuscation to the trace exporter](DataDog/libdatadog#1819)

### Describe how you validated your changes
- [x] unit test
- [x] system test

### Additional Notes


Co-authored-by: oscar.ledauphin <oscar.ledauphin@datadoghq.com>
Comment on lines +325 to +340
if obfuscation_active {
let span_type: &str = span.r#type.borrow();
let resource: &str = span.resource.borrow();
let dbms_hint: Option<&str> = span.meta.get("db.type").map(|v| v.borrow());
let obfuscated_resource =
libdd_trace_obfuscation::obfuscate::obfuscate_resource_for_stats(
span_type, resource, dbms_hint,
);
let wrapper = ObfuscatedStatSpan {
inner: span,
obfuscated_resource,
};
stats_concentrator.add_span(&wrapper);
} else {
stats_concentrator.add_span(span);
}
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.

I think the obfuscation should be done in the SpanConcentrator in the aggregation key computation. This will allow you to remove the ObfuscatedStatSpan

client_side_stats.store(Arc::new(StatsComputationStatus::Enabled {
stats_concentrator: stats_concentrator.clone(),
cancellation_token: cancellation_token.clone(),
obfuscation_active: new_obfuscation_active,
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.

If you want to avoid having to recreate the StatsExporter when obfuscation status is updated, you could use an Arc<AtomicBool> or ArcSwap<AtomicBool> (since it's not updated often). And share between the trace exporter and the stats exporter.

Comment on lines +340 to +363
let span_type: &str = span.r#type.borrow();
let resource: &str = span.resource.borrow();
let dbms_hint: Option<&str> = span.meta.get("db.type").map(|v| v.borrow());
let sql_obfuscation_mode = get_agent_info()
.and_then(|info| {
info.info.config.as_ref().and_then(|config| {
config
.obfuscation
.as_ref()
.map(|obfuscation_cfg| obfuscation_cfg.sql_obfuscation_mode)
})
})
.unwrap_or_default();
let config = StatsObfuscationConfig {
sql_obfuscation_mode,
};
let obfuscated_resource =
libdd_trace_obfuscation::obfuscate::obfuscate_resource_for_stats(
span_type, resource, dbms_hint, config,
);
let wrapper = ObfuscatedStatSpan {
inner: span,
obfuscated_resource,
};
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 obfuscation logic should live in the SpanConcentrator and be controlled by a obfuscation_enabled attribute in the SpanConcentrator (it can use the Arc from the stats exporter if it's easier). I don't think you need the ObfuscatedStatSpan either. This has the benefit of sharing the logic with serverless who also use the SpanConcentrator.

{
obfuscation_active.load(Ordering::Relaxed)
} else {
unreachable!()
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.

Use an error! log instead. We want to avoid panicking as much as possible.

Comment on lines +390 to +396
#[cfg(feature = "stats-obfuscation")]
let obfuscation_active = if let StatsComputationStatus::Enabled {
obfuscation_active, ..
} = &**status
{
obfuscation_active.load(Ordering::Relaxed)
} else {
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.

This is a bit convoluted because of the stats-obfuscation feature, I don't have all the background but is it required ?

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.

4 participants