[SVLS-7168] Create GCP PubSub Push Subscriptions Plugin
What does this PR do?
This PR adds comprehensive support for Google Cloud Pub/Sub push subscriptions, enabling distributed tracing for messages delivered via HTTP webhooks. Unlike pull subscriptions, where the application pulls for messages using the SDK, push subscriptions have GCP Pub/Sub POST messages directly to an HTTP endpoint.
New Plugin: pubsub-push-subscription.js
- Creates pubsub.delivery spans for incoming push subscription HTTP requests
- Intercepts HTTP requests with GCP-specific headers:
- User-Agent: APIs-Google; (+https://developers.google.com/webmasters/APIs-Google.html)
- x-goog-pubsub-subscription-name
- x-goog-pubsub-message-id
- Extracts trace context from message attributes (injected by producer)
- Parses message metadata (subscription name, topic, publish time)
- Finishes span when HTTP response completes
Modified: packages/datadog-instrumentations/src/http.js
- So the push subscription plugin must subscribe to
apm:http:server:request:startbefore the HTTP server plugin- Detect Pub/Sub push requests early
- Create pubsub.delivery span as active parent
- Ensure web framework spans (Express, Fastify, etc.) become children of the delivery span
Next PR in the batch is #6782
Motivation
An inferred span for the push subscription HTTP POST request to the Cloud Run service from a pub/sub topic Example full Push Distributed Trace of a cloud run service triggering another service using a push subscription
Plugin Checklist
- [x] Unit tests.
- [x] Integration tests.
- [x] Benchmarks.
- [ ] TypeScript definitions.
- [ ] TypeScript tests.
- [x] API documentation.
- [x] CI jobs/workflows.
Additional Notes
Critical for Distributed Tracing: When creating or updating a GCP Pub/Sub push subscription, you must include the --push-no-wrapper-write-metadata flag to enable trace context propagation. By default, GCP Pub/Sub wraps push messages in a JSON envelope and does not include message attributes as HTTP headers. We do not currently read the req.body for pubsub distributed tracing
Additional information can be found in this doc
Overall package size
Self size: 4.39 MB Deduped: 5.21 MB No deduping: 5.21 MB
Dependency sizes
| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 2.0.0 | 68.46 kB | 797.03 kB | | dc-polyfill | 0.1.10 | 26.73 kB | 26.73 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe
Codecov Report
:x: Patch coverage is 57.07965% with 97 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 84.49%. Comparing base (4b40f00) to head (89ad695).
:warning: Report is 5 commits behind head on master.
Additional details and impacted files
@@ Coverage Diff @@
## master #6260 +/- ##
==========================================
- Coverage 84.77% 84.49% -0.29%
==========================================
Files 522 523 +1
Lines 22233 22445 +212
==========================================
+ Hits 18849 18964 +115
- Misses 3384 3481 +97
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
- :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
Benchmarks
Benchmark execution time: 2025-12-20 19:33:31
Comparing candidate commit 89ad6956f0179bd6553988b69345f04a6225baee in PR branch nina.rei/SVLS-7168/gcp-push-pubsub-plugin with baseline commit 4b40f00f7860d074ad4346a17b164b5c57e409a4 in branch master.
Found 0 performance improvements and 2 performance regressions! Performance is the same for 288 metrics, 30 unstable metrics.
scenario:plugin-http-server-querystring-obfuscation-22
- 🟥
execution_time[+34.626ms; +38.625ms] or [+5.265%; +5.873%]
scenario:plugin-http-server-querystring-obfuscation-24
- 🟥
execution_time[+32.084ms; +35.046ms] or [+5.387%; +5.884%]
⚠️ Warnings
🧪 1 Test failed
OpenFeature "before all" hook for "should not crash build after installing with yarn"fromOpenFeature(Datadog) (Fix with Cursor)Command failed: yarn error https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.13.1.tgz: Request failed "500 Internal Server Error" error Error: ENOENT: no such file or directory, open '/home/runner/.cache/yarn/v6/npm-@datadog-pprof-5.13.1-51c540d75cf4471806db65d0686cbe0a96125ce2-integrity/node_modules/@datadog/pprof/.yarn-metadata.json' Error: Command failed: yarn error https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.13.1.tgz: Request failed "500 Internal Server Error" error Error: ENOENT: no such file or directory, open '/home/runner/.cache/yarn/v6/npm-@datadog-pprof-5.13.1-51c540d75cf4471806db65d0686cbe0a96125ce2-integrity/node_modules/@datadog/pprof/.yarn-metadata.json' at genericNodeError (node:internal/errors:985:15) at wrappedFn (node:internal/errors:539:14) ...
ℹ️ Info
❄️ No new flaky tests detected
This comment will be updated automatically if new data arrives.🔗 Commit SHA: 89ad695 | Docs | Datadog PR Page | Was this helpful? Give us feedback!
To use Codex here, create a Codex account and connect to github.
@codex review
@codex review
@codex review
We're definitely going to want a test with this.
For example we should simulate the situation where an HTTP request is received and it contains the Google pub sub user agent and headers and makes the appropriate span. Is the intent to only have the google pub sub span or also have an HTTP span with it? And which one is the parent? That's all stuff that should be a part of the test.
We're definitely going to want a test with this.
For example we should simulate the situation where an HTTP request is received and it contains the Google pub sub user agent and headers and makes the appropriate span. Is the intent to only have the google pub sub span or also have an HTTP span with it? And which one is the parent? That's all stuff that should be a part of the test.
I've tested many different situations, but an HTTP request will only ever include the Google PubSub headers and user agent when the request originates from PubSub with the flag as stated in Google's documentation, which means we need to handle that. I have another PR in progress to test all these changes, and I’ve already deployed the code to org 2 to verify the traces and ensure distributed traces are functioning correctly across different scenarios. I’ve specifically tested multiple frameworks and direct HTTP requests, both with and without the --push-no-wrapper-write-metadata flag, as well as all deployment methods for a Cloud Run service using Pub/Sub. I can update the test PR with more examples beyond what’s currently included in the other PRs' details.
As discused on Zoom please add an experimental env var to enable this functionality. Here's a recent example that shows the two config files that need updating and how to access the config in code:
https://github.com/DataDog/dd-trace-js/pull/6733
/merge
View all feedbacks in Devflow UI.
2025-12-19 22:58:29 UTC :information_source: Start processing command /merge
2025-12-19 22:58:44 UTC :information_source: MergeQueue: waiting for PR to be ready
This pull request is not mergeable according to GitHub. Common reasons include pending required checks, missing approvals, or merge conflicts — but it could also be blocked by other repository rules or settings.
It will be added to the queue as soon as checks pass and/or get approvals.
Note: if you pushed new commits since the last approval, you may need additional approval.
You can remove it from the waiting list with /remove command.
2025-12-20 02:59:15 UTC :warning: MergeQueue: This merge request was unqueued
devflow unqueued this merge request: It did not become mergeable within the expected time