Skip to content

chore(otel): make otel api a peer dependency - #6914

Closed
mabdinur wants to merge 42 commits into
masterfrom
munir/make-otel-api-a-peer-dependency
Closed

chore(otel): make otel api a peer dependency#6914
mabdinur wants to merge 42 commits into
masterfrom
munir/make-otel-api-a-peer-dependency

Conversation

@mabdinur

@mabdinur mabdinur commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

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

mabdinur commented Nov 14, 2025

Copy link
Copy Markdown
Contributor Author

Closed #6915. This is the right change

@BridgeAR BridgeAR 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.

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

@pr-commenter

pr-commenter Bot commented Nov 18, 2025

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-04-16 17:49:36

Comparing candidate commit 0633b0e in PR branch munir/make-otel-api-a-peer-dependency with baseline commit de1327b in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 1379 metrics, 105 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
Comment thread package.json Outdated
Comment thread package.json Outdated
@github-actions

github-actions Bot commented Nov 20, 2025

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 5.5 MB
Deduped: 6.34 MB
No deduping: 6.34 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.1 | 82.56 kB | 817.39 kB | | dc-polyfill | 0.1.10 | 26.73 kB | 26.73 kB |

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

@codecov

codecov Bot commented Nov 20, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.92308% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.59%. Comparing base (de1327b) to head (0633b0e).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
...ages/dd-trace/src/opentelemetry/check_peer_deps.js 69.23% 4 Missing ⚠️
packages/dd-trace/src/noop/proxy.js 80.00% 1 Missing ⚠️
packages/dd-trace/src/proxy.js 87.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6914      +/-   ##
==========================================
- Coverage   73.59%   73.59%   -0.01%     
==========================================
  Files         773      774       +1     
  Lines       36083    36105      +22     
==========================================
+ Hits        26557    26573      +16     
- Misses       9526     9532       +6     
Flag Coverage Δ
aiguard-macos 36.50% <0.00%> (-0.12%) ⬇️
aiguard-ubuntu 36.61% <0.00%> (-0.12%) ⬇️
aiguard-windows 36.41% <0.00%> (-0.12%) ⬇️
apm-capabilities-tracing-macos ?
apm-capabilities-tracing-ubuntu 48.24% <76.92%> (+0.02%) ⬆️
apm-capabilities-tracing-windows ?
apm-integrations-child-process 36.13% <0.00%> (-0.13%) ⬇️
apm-integrations-couchbase-18 35.15% <0.00%> (-0.12%) ⬇️
apm-integrations-couchbase-eol 35.20% <0.00%> (-0.09%) ⬇️
apm-integrations-oracledb 35.17% <0.00%> (-0.12%) ⬇️
appsec-express 52.87% <0.00%> (-0.10%) ⬇️
appsec-fastify 49.35% <0.00%> (-0.10%) ⬇️
appsec-graphql 49.61% <0.00%> (-0.20%) ⬇️
appsec-kafka 42.14% <0.00%> (-0.11%) ⬇️
appsec-ldapjs 41.46% <0.00%> (-0.11%) ⬇️
appsec-lodash 41.48% <0.00%> (-0.11%) ⬇️
appsec-macos ?
appsec-mongodb-core 46.08% <0.00%> (-0.14%) ⬇️
appsec-mongoose 46.68% <0.00%> (-0.10%) ⬇️
appsec-mysql 48.83% <0.00%> (-0.10%) ⬇️
appsec-node-serialize 40.66% <0.00%> (-0.11%) ⬇️
appsec-passport 44.65% <0.00%> (-0.11%) ⬇️
appsec-postgres 48.41% <0.00%> (-0.13%) ⬇️
appsec-sourcing 40.15% <0.00%> (-0.11%) ⬇️
appsec-stripe 42.38% <0.00%> (-0.11%) ⬇️
appsec-template 40.82% <0.00%> (-0.11%) ⬇️
appsec-ubuntu 56.86% <0.00%> (-0.10%) ⬇️
appsec-windows ?
instrumentations-instrumentation-bluebird 29.83% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-body-parser 37.73% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-child_process 35.51% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-cookie-parser 31.75% <0.00%> (-0.11%) ⬇️
instrumentations-instrumentation-express 31.97% <0.00%> (-0.11%) ⬇️
instrumentations-instrumentation-express-mongo-sanitize 31.87% <0.00%> (-0.11%) ⬇️
instrumentations-instrumentation-express-session 37.36% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-fs 29.49% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-generic-pool 30.99% <ø> (ø)
instrumentations-instrumentation-http 36.96% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-knex 29.80% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-mongoose 30.90% <0.00%> (-0.11%) ⬇️
instrumentations-instrumentation-multer 37.50% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-mysql2 35.48% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-passport 41.24% <0.00%> (-0.11%) ⬇️
instrumentations-instrumentation-passport-http 40.93% <0.00%> (-0.11%) ⬇️
instrumentations-instrumentation-passport-local 41.43% <0.00%> (-0.11%) ⬇️
instrumentations-instrumentation-pg 35.00% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-promise 29.76% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-promise-js 29.77% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-q 29.80% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-url 29.76% <0.00%> (-0.12%) ⬇️
instrumentations-instrumentation-when 29.78% <0.00%> (-0.12%) ⬇️
llmobs-ai 38.44% <0.00%> (-0.12%) ⬇️
llmobs-anthropic 37.89% <0.00%> (-0.11%) ⬇️
llmobs-bedrock 37.15% <0.00%> (-0.11%) ⬇️
llmobs-google-genai 37.58% <0.00%> (-0.11%) ⬇️
llmobs-langchain 37.03% <0.00%> (-0.10%) ⬇️
llmobs-openai 41.26% <0.00%> (-0.11%) ⬇️
llmobs-vertex-ai 37.75% <0.00%> (-0.12%) ⬇️
platform-core 30.01% <ø> (ø)
platform-esbuild 32.83% <ø> (ø)
platform-instrumentations-misc 40.24% <ø> (ø)
platform-shimmer 35.73% <ø> (ø)
platform-unit-guardrails 31.38% <ø> (ø)
platform-webpack 20.82% <0.00%> (-0.02%) ⬇️
plugins-azure-durable-functions 25.21% <ø> (ø)
plugins-azure-event-hubs 25.36% <ø> (ø)
plugins-azure-service-bus 24.78% <ø> (ø)
plugins-bullmq 40.78% <0.00%> (-0.12%) ⬇️
plugins-cassandra 35.31% <0.00%> (-0.12%) ⬇️
plugins-cookie 26.33% <ø> (ø)
plugins-cookie-parser 26.14% <ø> (ø)
plugins-crypto 25.66% <ø> (ø)
plugins-dd-trace-api 35.45% <0.00%> (-0.12%) ⬇️
plugins-express-mongo-sanitize 26.28% <ø> (ø)
plugins-express-session 26.10% <ø> (ø)
plugins-fastify 39.41% <0.00%> (-0.12%) ⬇️
plugins-fetch 35.82% <0.00%> (-0.12%) ⬇️
plugins-fs 35.73% <0.00%> (-0.12%) ⬇️
plugins-generic-pool 25.25% <ø> (ø)
plugins-google-cloud-pubsub 43.09% <0.00%> (-0.11%) ⬇️
plugins-grpc 38.09% <0.00%> (-0.12%) ⬇️
plugins-handlebars 26.32% <ø> (ø)
plugins-hapi 37.33% <0.00%> (-0.12%) ⬇️
plugins-hono 37.57% <0.00%> (-0.12%) ⬇️
plugins-ioredis 35.77% <0.00%> (-0.12%) ⬇️
plugins-knex 26.01% <ø> (ø)
plugins-langgraph 35.12% <0.00%> (-0.12%) ⬇️
plugins-ldapjs 23.88% <ø> (ø)
plugins-light-my-request 25.75% <ø> (ø)
plugins-limitd-client 30.04% <0.00%> (-0.12%) ⬇️
plugins-lodash 25.33% <ø> (ø)
plugins-mariadb 36.65% <0.00%> (-0.12%) ⬇️
plugins-memcached 35.42% <0.00%> (-0.12%) ⬇️
plugins-microgateway-core 36.41% <0.00%> (-0.12%) ⬇️
plugins-moleculer 38.12% <0.00%> (-0.12%) ⬇️
plugins-mongodb 36.51% <0.00%> (-0.12%) ⬇️
plugins-mongodb-core 36.26% <0.00%> (-0.09%) ⬇️
plugins-mongoose 36.10% <0.00%> (-0.20%) ⬇️
plugins-multer 26.10% <ø> (ø)
plugins-mysql 36.51% <0.00%> (-0.12%) ⬇️
plugins-mysql2 36.49% <0.00%> (-0.12%) ⬇️
plugins-node-serialize 26.37% <ø> (ø)
plugins-opensearch 35.07% <0.00%> (-0.12%) ⬇️
plugins-passport-http 26.16% <ø> (ø)
plugins-postgres 34.46% <0.00%> (-0.11%) ⬇️
plugins-process 25.66% <ø> (ø)
plugins-pug 26.33% <ø> (ø)
plugins-redis 35.93% <0.00%> (-0.12%) ⬇️
plugins-router 39.98% <0.00%> (-0.12%) ⬇️
plugins-sequelize 25.03% <ø> (ø)
plugins-test-and-upstream-amqp10 35.74% <0.00%> (-0.12%) ⬇️
plugins-test-and-upstream-amqplib 40.93% <0.00%> (-0.13%) ⬇️
plugins-test-and-upstream-apollo 36.59% <0.00%> (-0.11%) ⬇️
plugins-test-and-upstream-avsc 35.59% <0.00%> (-0.12%) ⬇️
plugins-test-and-upstream-bunyan 31.19% <0.00%> (-0.12%) ⬇️
plugins-test-and-upstream-connect 37.92% <0.00%> (-0.12%) ⬇️
plugins-test-and-upstream-graphql 37.27% <0.00%> (-0.12%) ⬇️
plugins-test-and-upstream-koa 37.53% <0.00%> (-0.12%) ⬇️
plugins-test-and-upstream-protobufjs 35.80% <0.00%> (-0.12%) ⬇️
plugins-test-and-upstream-rhea 41.01% <0.00%> (-0.13%) ⬇️
plugins-undici 36.60% <0.00%> (-0.11%) ⬇️
plugins-url 25.66% <ø> (ø)
plugins-valkey 35.44% <0.00%> (-0.13%) ⬇️
plugins-vm 25.66% <ø> (ø)
plugins-winston 31.63% <0.00%> (+0.01%) ⬆️
plugins-ws 39.05% <0.00%> (-0.12%) ⬇️
profiling-macos 38.00% <0.00%> (-0.12%) ⬇️
profiling-ubuntu 38.16% <0.00%> (-0.12%) ⬇️
profiling-windows 39.53% <0.00%> (-0.12%) ⬇️
serverless-azure-functions-client 25.10% <ø> (ø)
serverless-azure-functions-eventhubs 25.10% <ø> (ø)
serverless-azure-functions-servicebus 25.10% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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

datadog-official Bot commented Nov 20, 2025

Copy link
Copy Markdown

Tests

Fix all issues with BitsAI or with Cursor

⚠️ Other Violations

🧪 1 Test failed

"before each" hook for "should properly set request host with IPv6" from Mocha Tests   View in Datadog   (Fix with Cursor)
Attempted to wrap request which is already wrapped
TypeError: Attempted to wrap request which is already wrapped
    at checkWrappedMethod (node_modules\sinon\lib\sinon\util\core\wrap-method.js:67:21)
    at wrapMethod (node_modules\sinon\lib\sinon\util\core\wrap-method.js:132:13)
    at spy (node_modules\sinon\lib\sinon\spy.js:178:16)
    at Sandbox.spy (node_modules\sinon\lib\sinon\sandbox.js:433:37)
    at Context.<anonymous> (packages\dd-trace\test\exporters\common\request.spec.js:348:15)
    at process.processImmediate (node:internal/timers:504:21)
--------------
Error: Stack Trace for original
...

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 65.38%
Overall Coverage: 68.00% (-0.01%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 0633b0e | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or 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
Comment thread LICENSE-3rdparty.csv Outdated
Comment thread package.json Outdated
Comment thread integration-tests/opentelemetry.spec.js Outdated
Comment thread scripts/check_licenses.js Outdated
Comment thread docs/API.md
@mabdinur
mabdinur requested review from a team as code owners March 4, 2026 19:09
Comment thread package.json Outdated
Comment thread package.json Outdated
@mabdinur
mabdinur force-pushed the munir/make-otel-api-a-peer-dependency branch from 055922e to 09caa3c Compare March 11, 2026 16:52
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mabdinur
mabdinur force-pushed the munir/make-otel-api-a-peer-dependency branch from 10423e0 to b63fbec Compare March 26, 2026 20:28

@BridgeAR BridgeAR 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.

This is looking very good! Just the exc-parser needs to be fixed and the linter for the license. The version should ideally be open ended for testing and if possible, we could find a way to not have the noop provider. Having the noop one will likely otherwise cause problems at some point if the APIs deviate / expectations are not met.

Comment thread integration-tests/opentelemetry.spec.js Outdated
Comment on lines +3 to +12
const noopSpan = {
spanContext: () => ({}),
setAttribute: () => {},
setAttributes: () => {},
addEvent: () => {},
updateName: () => {},
setStatus: () => {},
end: () => {},
isRecording: () => false,
}

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.

Would it be possible to prevent creating the noop tracer provider somehow so that this will just never be accessed anywhere in case it is not there?
That would be nicer, since the noop one otherwise needs to stay in sync and that is likely to deviate soon.

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.

Yup, we can raise an error if TracerProvider is accessed when one isn't registered. A noop TracerProvider can allow tracing to fail silently. It better if we are noisy about it.

Comment thread package.json Outdated
@mabdinur
mabdinur requested a review from BridgeAR April 13, 2026 15:08
Comment on lines +95 to +100
const NoopProxy = proxyquire.noPreserveCache()('../../src/noop/proxy', {
'../opentelemetry/check_peer_deps': noopCheckPeerDeps,
})
const getter = Object.getOwnPropertyDescriptor(NoopProxy.prototype, 'TracerProvider').get
const NoopClass = getter.call({})
assert.throws(() => new NoopClass(), { message: expectedMessage })

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.

Could you please change these tests to ones how a user could actually reach this point? These are directly calling in internals in a way that a user would not be. With that, we are uncertain if this is indeed the triggered behavior.

Comment on lines +391 to +397
return class {
constructor () {
throw new Error(
'@opentelemetry/api is required to use TracerProvider. ' +
'Install it with: npm install @opentelemetry/api'
)
}

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.

I like this, it is a neat way of doing this! I am just unsure if we really want to throw or if logging a warning here would be best instead and to gracefully handle it otherwise. I am unsure, if that is an option. Handling it gracefully would probably require the noop tracer again?

I would have to know how the user could reach this to decide on what to do.

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.

The main documented usage is

const tracerProvider = new tracer.TracerProvider()
:

  const tracer = require('dd-trace').init()                                                                           
  const tracerProvider = new tracer.TracerProvider()        
  tracerProvider.register()     

IMO we should deprecate this. Instead, dd-trace should auto-register its TracerProvider during .init() when @opentelemetry/api is present (similar to how we handle otel logs and metrics). Then users could then just do:

  require('dd-trace').init()                                
  // dd-trace auto-registers — use the standard OTel API from here 
  const { trace } = require("@opentelemetry/api");                                                   
  const provider = trace.getTracerProvider()   

This keeps dd-trace's OTel surface minimal and aligns with how the OTel ecosystem expects providers to be set up.

We can do this in a future PR

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.

Conceptually, I like that. The question I have is: how can we do that without providing loading overhead for people not using Otel? I guess it could work as a hook: the hook is our activation trigger. @rochdev what do you think?

That aside: what shall we do short term with this? Our tracer should normally handle things gracefully and this would not be the case anymore. I think this is fine as a major version, I am not yet sure about before. @rochdev @bengl opinions?
We would have to document that change though.

@mabdinur mabdinur closed this Apr 18, 2026
@mabdinur

Copy link
Copy Markdown
Contributor Author

Closing to reduce noise. Will reopen when this change is in a better place

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