-
Notifications
You must be signed in to change notification settings - Fork 304
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
[DEBUG-2972] Add initial support for Code Origin for Spans (Fastify entry spans only) #4449
base: master
Are you sure you want to change the base?
Conversation
Overall package sizeSelf size: 7.45 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | @datadog/native-appsec | 8.1.1 | 18.67 MB | 18.68 MB | | @datadog/native-iast-taint-tracking | 3.1.0 | 12.27 MB | 12.28 MB | | @datadog/pprof | 5.3.0 | 9.85 MB | 10.22 MB | | protobufjs | 7.2.5 | 2.77 MB | 5.16 MB | | @datadog/native-iast-rewriter | 2.5.0 | 2.51 MB | 2.59 MB | | @opentelemetry/core | 1.14.0 | 872.87 kB | 1.47 MB | | @datadog/native-metrics | 2.0.0 | 898.77 kB | 1.3 MB | | @opentelemetry/api | 1.8.0 | 1.21 MB | 1.21 MB | | jsonpath-plus | 9.0.0 | 580.4 kB | 1.03 MB | | import-in-the-middle | 1.11.2 | 112.74 kB | 826.22 kB | | msgpack-lite | 0.1.26 | 201.16 kB | 281.59 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | pprof-format | 2.1.0 | 111.69 kB | 111.69 kB | | @datadog/sketches-js | 2.1.0 | 109.9 kB | 109.9 kB | | semver | 7.6.3 | 95.82 kB | 95.82 kB | | lodash.sortby | 4.7.0 | 75.76 kB | 75.76 kB | | lru-cache | 7.14.0 | 74.95 kB | 74.95 kB | | ignore | 5.3.1 | 51.46 kB | 51.46 kB | | int64-buffer | 0.1.10 | 49.18 kB | 49.18 kB | | shell-quote | 1.8.1 | 44.96 kB | 44.96 kB | | istanbul-lib-coverage | 3.2.0 | 29.34 kB | 29.34 kB | | rfdc | 1.3.1 | 25.21 kB | 25.21 kB | | tlhunter-sorted-set | 0.1.0 | 24.94 kB | 24.94 kB | | limiter | 1.1.5 | 23.17 kB | 23.17 kB | | dc-polyfill | 0.1.4 | 23.1 kB | 23.1 kB | | retry | 0.13.1 | 18.85 kB | 18.85 kB | | jest-docblock | 29.7.0 | 8.99 kB | 12.76 kB | | crypto-randomuuid | 1.0.0 | 11.18 kB | 11.18 kB | | koalas | 1.0.2 | 6.47 kB | 6.47 kB | | path-to-regexp | 0.1.10 | 6.38 kB | 6.38 kB | | module-details-from-path | 1.0.3 | 4.47 kB | 4.47 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #4449 +/- ##
===========================================
- Coverage 88.04% 65.95% -22.09%
===========================================
Files 294 285 -9
Lines 12266 12359 +93
Branches 33 33
===========================================
- Hits 10799 8151 -2648
- Misses 1467 4208 +2741 ☔ View full report in Codecov by Sentry. |
4f6732a
to
cf52e47
Compare
cf52e47
to
297bdfa
Compare
This stack of pull requests is managed by Graphite. Learn more about stacking. |
297bdfa
to
2ff305f
Compare
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.
very cool
|
||
return returnTopUserLandFrameOnly | ||
? callsite | ||
: (i === 0 ? callsites : callsites.slice(i)) |
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.
not sure I follow this logic...
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.
The algorithm is as follows:
We start with an array of callsites. The top n callsites might not be user-land callsites, so we want to remove those from the array. In case i === 0
it means that the top callsite is actually a user-land frame, so there's no need to slice the array (which will shallow-clone it). Additionally, we want to limit the number of frames to limit
. If there's less callsites in the array then the max limit
and i === 0
, again, there's no need to call slice
.
2ff305f
to
bdbed4f
Compare
bdbed4f
to
5c53936
Compare
This commit does two things: 1. It lays the groundwork for a new feature called "Code Origin for Spans". 2. To showcase this feature, it adds limited support for just Fastify entry-spans. To enable, set `DD_CODE_ORIGIN_FOR_SPANS_ENABLED=true`.
5c53936
to
4d48155
Compare
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.
LGTM. Only some minor comments
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.
LGTM, but it might be worth waiting for some reviewer with more experience with the fastify plugin 😄
@@ -27,6 +28,11 @@ function wrapFastify (fastify, hasParsingEvents) { | |||
app.addHook('preHandler', preValidation) | |||
} | |||
|
|||
// No need to add the onRoute hook unless Code Origin for Spans is enabled | |||
if (codeOriginForSpansChannel.hasSubscribers) { |
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 should be in the hook instead because subscribers can be enabled/disabled at runtime.
@@ -5,6 +5,7 @@ const { addHook, channel, AsyncResource } = require('./helpers/instrument') | |||
|
|||
const errorChannel = channel('apm:fastify:middleware:error') | |||
const handleChannel = channel('apm:fastify:request:handle') | |||
const codeOriginForSpansChannel = channel('datadog:code-origin-for-spans') |
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.
There shouldn't be explicit references to tracing in instrumentation.
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.
Also, channels are easier to reason about if they match the event that they represent. For example, different subscribers may be interested in different aspects of routing, so it would be better to have something like a routeChannel instead which would add the route when any subscriber is interested in that.
this.setFramework(req, 'fastify', this.config) | ||
const tags = routeConfig?.[kCodeOriginForSpansTagsSym] | ||
if (tags) this.setSpanTags(req, tags) |
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.
Could this be done in a separate plugin instead? The reasoning is that adding product-specific code directly to plugin increases size and complexity even when those products are not used, whereas we could disable product-specific plugins entirely and not even import them when a product is disabled for example.
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.
That would actually also remove the need to modify web
since you could then have something like setOrigin
on your di-specific base class.
@@ -542,7 +542,193 @@ describe('Plugin', () => { | |||
}) | |||
} | |||
}) | |||
|
|||
describe('with tracer config codeOriginForSpansEnabled', () => { |
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.
Is this name Node-specific or has it been standardized? Mostly asking because it exposes implementation details in the name.
What does this PR do?
Note: This PR relates to an upcoming Datadog feature that's not available yet.
This PR does two things:
To enable, set
DD_CODE_ORIGIN_FOR_SPANS_ENABLED=true
.This feature will, in its most basic form, allow users to see where in their code base a span was started/created.
Code origin is only set for spans whos callstack contains user land stack frames.
For reference, here's a PR that implements Code Origin in the Java tracer: DataDog/dd-trace-java#7001
Motivation
This makes it easier to understand what each span shown in the flame graph represents.
Performance considerations
Keeping high performance in mind, we'll only compute the code origin for certain pre-defined span types. Specifically what we call entry and exit spans.
Scope
Adding support for all types of entry and exist spans in a single PR will make it harder to review, so this PR will only concern itself with adding support for Fastify entry spans; That is spans representing incoming HTTP requests to a Fastify app.
Middlewares have to be handled in a special way, as a middleware might respond early to an incoming HTTP request in which case the route handler is never called. In that instance, we want to the code origin to point to where the middleware function was registered. Doing that for Fastify however, is out of scope of this PR and support for this will be added in an upcoming PR.
Note to reviewers
Since this feature has not yet been rolled out to staging, you need a hash-link to test it. If you need access, please contact me.
Tasks