-
Notifications
You must be signed in to change notification settings - Fork 344
[SVLS-7168] Create inferred Span for GCP Push Subscriptions (including Cloud Events) #6320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: nina.rei/SVLS-7168/gcp-push-pubsub-plugin
Are you sure you want to change the base?
Conversation
Overall package sizeSelf size: 11.92 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | @datadog/libdatadog | 0.7.0 | 35.02 MB | 35.02 MB | | @datadog/native-appsec | 10.1.0 | 20.37 MB | 20.37 MB | | @datadog/native-iast-taint-tracking | 4.0.0 | 11.72 MB | 11.73 MB | | @datadog/pprof | 5.9.0 | 9.77 MB | 10.1 MB | | @opentelemetry/core | 1.30.1 | 908.66 kB | 7.16 MB | | protobufjs | 7.5.4 | 2.95 MB | 5.6 MB | | @datadog/wasm-js-rewriter | 4.0.1 | 2.85 MB | 3.58 MB | | @datadog/native-metrics | 3.1.1 | 1.02 MB | 1.43 MB | | @opentelemetry/api | 1.8.0 | 1.21 MB | 1.21 MB | | jsonpath-plus | 10.3.0 | 617.18 kB | 1.08 MB | | import-in-the-middle | 1.14.2 | 122.36 kB | 850.93 kB | | lru-cache | 10.4.3 | 804.3 kB | 804.3 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.1.0 | 111.69 kB | 111.69 kB | | @datadog/sketches-js | 2.1.1 | 109.9 kB | 109.9 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 | | @isaacs/ttlcache | 1.4.1 | 25.2 kB | 25.2 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 | | koalas | 1.0.2 | 6.47 kB | 6.47 kB | | module-details-from-path | 1.0.4 | 3.96 kB | 3.96 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## nina.rei/SVLS-7168/gcp-push-pubsub-plugin #6320 +/- ##
=============================================================================
- Coverage 83.25% 83.11% -0.15%
=============================================================================
Files 478 478
Lines 20177 20205 +28
=============================================================================
- Hits 16798 16793 -5
- Misses 3379 3412 +33 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
BenchmarksBenchmark execution time: 2025-08-25 15:16:10 Comparing candidate commit 49bc6e8 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 1268 metrics, 55 unstable metrics. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just left some suggestions and I mark this as a draft, since it is a follow-up PR, if I understand correct.
Please change that, if that's incorrect.
if (!msg.attributes['x-dd-publish-start-time']) { | ||
msg.attributes['x-dd-publish-start-time'] = String(Date.now()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
if (!msg.attributes['x-dd-publish-start-time']) { | |
msg.attributes['x-dd-publish-start-time'] = String(Date.now()) | |
} | |
msg.attributes['x-dd-publish-start-time'] ??= String(Date.now()) |
if (publishStartTimeRaw) { | ||
const publishStartTime = Number.parseInt(publishStartTimeRaw, 10) | ||
if (Number.isFinite(publishStartTime) && publishStartTime > 0) { | ||
const messageId = (message && message.messageId) || req.headers['ce-id'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const messageId = (message && message.messageId) || req.headers['ce-id'] | |
const messageId = message?.messageId || req.headers['ce-id'] |
const t0 = Number.parseInt(publishStartTimeRawForHttp, 10) | ||
if (Number.isFinite(t0) && t0 > 0) schedulingMs = Date.now() - t0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks rather complicated. What values can we expect in such attribute? I guess we could potentially simplify it a tad :)
The same applies below.
startTime: publishStartTime | ||
}) | ||
const deliveryEnd = Date.now() | ||
try { deliverySpan.setTag('pubsub.delivery.duration_ms', deliveryEnd - publishStartTime) } catch {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try { deliverySpan.setTag('pubsub.delivery.duration_ms', deliveryEnd - publishStartTime) } catch {} | |
deliverySpan.setTag('pubsub.delivery.duration_ms', deliveryEnd - publishStartTime) |
It would be very bad if setTag()
would fail.
startTime: publishStartTime | ||
}) | ||
const deliveryEnd = Date.now() | ||
try { deliverySpan.setTag('pubsub.delivery.duration_ms', deliveryEnd - publishStartTime) } catch {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would the duration on the span not be sufficient here?
const publishStartTime = Number.parseInt(publishStartTimeRaw, 10) | ||
if (Number.isFinite(publishStartTime) && publishStartTime > 0) { | ||
const messageId = (message && message.messageId) || req.headers['ce-id'] | ||
const deliveryTags = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const deliveryTags = { | |
const tags = { |
I think it's fine to use the shorter name. We always want to deliver tags :)
if (req.headers['ce-time']) deliveryTags['cloudevents.time'] = req.headers['ce-time'] | ||
deliveryTags['eventarc.trigger'] = 'pubsub' | ||
} | ||
const deliverySpan = this.tracer.startSpan('pubsub.delivery', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const deliverySpan = this.tracer.startSpan('pubsub.delivery', { | |
const span = this.tracer.startSpan('pubsub.delivery', { |
I guess span would also be fine here?
What does this PR do?
Extends the official PubSub plugin capabilities and optimizes Datadog tracing instrumentation for Google Cloud Pub/Sub push messages and Cloud Events across all Node.js web frameworks.
GCP sends push → HTTP server receives POST request
Plugin detects → "This is a Pub/Sub push!" (via User-Agent: APIs-Google)
Plugin creates → PubSub.delivery synthetic span with parent trace id from producer cloud run service (This will be reworked in another PR)
Plugin creates → HTTP span as child of PubSub span
Express inherits → Express spans inherit via scope activation
Your app processes → Business logic with automatic tracing
This makes the spans have this hierarchy :
pubsub.delivery (created by gcp-pubsub-push.js)
└── http.request (manually created as child)
└── express.request (inherits via scope activation)
└── express.middleware (inherits via scope activation)
└── your-business-logic (main.js)
Follow-up PR will be opened to create the synthetic span in the flame graph
Motivation
An inferred span for the HTTP push post to the Cloud Run service from a pub/sub topic
Example full Push Direct Span of a cloud run service triggering another service using a direct push subscription
Example full Eventarc pubsub trigger span of a cloud run service triggering another service using an Eventarc cloud event trigger
Plugin Checklist
Additional Notes
The changes had to be made in server.js because in Push Subscription, the Cloud Run Service receives HTTP Requests.
Follow-up PR to #6260
Additional information can be found in this doc