Skip to content

Conversation

@mabdinur
Copy link
Contributor

@mabdinur mabdinur commented Nov 14, 2025

Resolves: #6882

What does this PR do?

Converts @opentelemetry/api and @opentelemetry/api-logs from regular dependencies to peer dependencies, and bumps the tested OpenTelemetry API version from v1.8.0 to v1.9.0.

Motivation

When users install a different version of @opentelemetry/api than what dd-trace bundles, npm can create two separate instances of the module. This breaks the OpenTelemetry singleton pattern - dd-trace sets the tracer/logger provider delegate on one instance while user code imports from the other. The result is custom spans becoming no-ops with all-zero trace IDs and log records not being captured

Making these peer dependencies ensures only one instance exists in the dependency tree, which is the standard pattern for singleton modules like OpenTelemetry API.

Risk

Converting Opentelemetry API has the potential to break applications that expect the dd-trace-js to bundle opentelemetry interfaces. This could be considered a breaking change.

Additional Notes

@mabdinur mabdinur force-pushed the munir/make-otel-api-a-peer-dependency branch from f79a175 to 2ba638d Compare November 14, 2025 14:11
@mabdinur
Copy link
Contributor Author

mabdinur commented Nov 14, 2025

Closed #6915. This is the right change

Copy link
Collaborator

@BridgeAR BridgeAR left a comment

Choose a reason for hiding this comment

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

This will need the yarn lock file being updated (just running yarn is enough).

@pr-commenter
Copy link

pr-commenter bot commented Nov 18, 2025

Benchmarks

Benchmark execution time: 2025-11-26 16:41:29

Comparing candidate commit 11589bb in PR branch munir/make-otel-api-a-peer-dependency with baseline commit 2fd9b1d in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 292 metrics, 28 unstable metrics.

@mabdinur mabdinur marked this pull request as ready for review November 20, 2025 06:35
@mabdinur mabdinur requested a review from a team as a code owner November 20, 2025 06:35
@github-actions
Copy link

github-actions bot commented Nov 20, 2025

Overall package size

Self size: 13.42 MB
Deduped: 104.48 MB
No deduping: 104.88 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | @datadog/libdatadog | 0.7.0 | 35.02 MB | 35.02 MB | | @datadog/native-appsec | 10.3.0 | 20.73 MB | 20.74 MB | | @datadog/pprof | 5.12.0 | 11.19 MB | 11.57 MB | | @datadog/native-iast-taint-tracking | 4.1.0 | 9.01 MB | 9.02 MB | | protobufjs | 7.5.4 | 2.95 MB | 5.83 MB | | @datadog/wasm-js-rewriter | 5.0.1 | 2.82 MB | 3.53 MB | | @datadog/native-metrics | 3.1.1 | 1.02 MB | 1.43 MB | | jsonpath-plus | 10.3.0 | 617.18 kB | 1.08 MB | | import-in-the-middle | 1.15.0 | 127.66 kB | 856.24 kB | | lru-cache | 10.4.3 | 804.3 kB | 804.3 kB | | @datadog/openfeature-node-server | 0.2.0 | 118.51 kB | 437.19 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | source-map | 0.7.6 | 185.63 kB | 185.63 kB | | pprof-format | 2.2.1 | 163.06 kB | 163.06 kB | | @datadog/sketches-js | 2.1.1 | 109.9 kB | 109.9 kB | | @isaacs/ttlcache | 2.1.2 | 90.79 kB | 90.79 kB | | lodash.sortby | 4.7.0 | 75.76 kB | 75.76 kB | | ignore | 7.0.5 | 63.38 kB | 63.38 kB | | istanbul-lib-coverage | 3.2.2 | 34.37 kB | 34.37 kB | | rfdc | 1.4.1 | 27.15 kB | 27.15 kB | | dc-polyfill | 0.1.10 | 26.73 kB | 26.73 kB | | tlhunter-sorted-set | 0.1.0 | 24.94 kB | 24.94 kB | | shell-quote | 1.8.3 | 23.74 kB | 23.74 kB | | limiter | 1.1.5 | 23.17 kB | 23.17 kB | | retry | 0.13.1 | 18.85 kB | 18.85 kB | | semifies | 1.0.0 | 15.84 kB | 15.84 kB | | jest-docblock | 29.7.0 | 8.99 kB | 12.76 kB | | crypto-randomuuid | 1.0.0 | 11.18 kB | 11.18 kB | | ttl-set | 1.0.0 | 4.61 kB | 9.69 kB | | mutexify | 1.4.0 | 5.71 kB | 8.74 kB | | path-to-regexp | 0.1.12 | 6.6 kB | 6.6 kB | | module-details-from-path | 1.0.4 | 3.96 kB | 3.96 kB | | escape-string-regexp | 5.0.0 | 3.66 kB | 3.66 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@codecov
Copy link

codecov bot commented Nov 20, 2025

Codecov Report

❌ Patch coverage is 66.66667% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.76%. Comparing base (2fd9b1d) to head (11589bb).
⚠️ Report is 28 commits behind head on master.

Files with missing lines Patch % Lines
...ages/dd-trace/src/opentelemetry/check_peer_deps.js 62.50% 9 Missing ⚠️
packages/dd-trace/src/noop/proxy.js 0.00% 4 Missing ⚠️
...dd-trace/src/opentelemetry/noop/tracer_provider.js 85.71% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6914      +/-   ##
==========================================
+ Coverage   84.60%   84.76%   +0.15%     
==========================================
  Files         505      515      +10     
  Lines       21167    21566     +399     
==========================================
+ Hits        17909    18281     +372     
- Misses       3258     3285      +27     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 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-official
Copy link

datadog-official bot commented Nov 20, 2025

⚠️ Tests

⚠️ Warnings

🧪 317 Tests failed

tests.parametric.test_128_bit_traceids.Test_128_Bit_Traceids.test_b3multi_128_bit_generation_disabled[library_env0, parametric-nodejs] from system_tests_suite (Datadog)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

self = <urllib3.connectionpool.HTTPConnectionPool object at 0x7fc287732390>
method = 'POST', url = '/trace/otel/flush', body = b'{"seconds": 1}'
headers = {'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '14', 'Content-Type': 'application/json'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
...
tests.parametric.test_128_bit_traceids.Test_128_Bit_Traceids.test_b3multi_128_bit_generation_enabled[library_env0, parametric-nodejs] from system_tests_suite (Datadog)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

self = <urllib3.connectionpool.HTTPConnectionPool object at 0x7fc2561e3b00>
method = 'POST', url = '/trace/otel/flush', body = b'{"seconds": 1}'
headers = {'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '14', 'Content-Type': 'application/json'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
...
tests.parametric.test_128_bit_traceids.Test_128_Bit_Traceids.test_b3multi_128_bit_propagation_and_generation[library_env0, parametric-nodejs] from system_tests_suite (Datadog)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

self = <urllib3.connectionpool.HTTPConnectionPool object at 0x7f16a1a99f10>
method = 'POST', url = '/trace/otel/flush', body = b'{"seconds": 1}'
headers = {'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '14', 'Content-Type': 'application/json'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
...
View all

ℹ️ Info

❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 11589bb | Docs | Datadog PR Page | Was this helpful? Give us feedback!

@mabdinur mabdinur enabled auto-merge (squash) November 20, 2025 07:02
@mabdinur mabdinur force-pushed the munir/make-otel-api-a-peer-dependency branch from 57e5122 to 0162595 Compare November 20, 2025 14:47
@mabdinur mabdinur changed the title chore(otel): make otel api peer dependency chore(otel): make otel api a peer dependency Nov 20, 2025
package.json Outdated
"@openfeature/core": "^1.9.0",
"@openfeature/server-sdk": "~1.20.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/api-logs": "^0.208.0",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use the identical range as the peer dependency ones. Otherwise we might test something else than the user.

const devDeps = new Set(Object.keys(pkg.devDependencies || {}))
const peerDeps = new Set(Object.keys(pkg.peerDependencies || {}))
const deps = new Set(Object.keys(pkg.dependencies || {}).filter(dep => !peerDeps.has(dep)))
const devDeps = new Set(Object.keys(pkg.devDependencies || {}).filter(dep => !peerDeps.has(dep)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I do not think we should filter anything here. Was there a specific reason why that's done?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, there was a linting error since I removed the licenses for the opentelemetry api package. So I made this change to avoid checking licenses for peer dependencies 😆 😰.

I should've dug a bit deeper and noticed that we DO set licenses on peer dependencies (ex: openfeatures).

<h2 id="opentelemetry-api">OpenTelemetry Compatibility</h2>

This library is OpenTelemetry compliant. Use the [OpenTelemetry API](https://opentelemetry.io/docs/instrumentation/js/) and the Datadog Tracer (dd-trace) library to measure execution times for specific pieces of code. In the following example, a Datadog TracerProvider is registered with @opentelemetry/api:
This library is OpenTelemetry compliant. The OpenTelemetry API packages (`@opentelemetry/api` and `@opentelemetry/api-logs`) are peer dependencies and must be installed separately.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we add a warning in case a user tries to use any of the otel APIs with a missing dependency and a potential fix?

@rochdev or @bengl PTAL. I am uncertain in what way it is fine to log the warning or not.

@mabdinur mabdinur requested a review from a team as a code owner November 23, 2025 02:11
@mabdinur mabdinur requested review from khanayan123 and removed request for a team November 23, 2025 02:11
@mabdinur mabdinur requested a review from a team as a code owner November 24, 2025 14:32
@mabdinur mabdinur marked this pull request as draft November 24, 2025 21:40
auto-merge was automatically disabled November 24, 2025 21:40

Pull request was converted to draft

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.

[BUG]: @opentelemetry/api version compatibility issue: TracerProvider produces no-op spans with versions >1.4.1

3 participants