-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(opentelemetry): Fix span & sampling propagation (#11092)
OK, this was a tricky one, but I _think_ it now works as expected. This PR fixes to fundamental issues with sampling & propagation that were uncovered by @Lms24 & myself while trying to use OTEL for remix & sveltekit: 1. `continueTrace` updates the propagation context, but if there is an active parent span (even a remote one) this is ignored. 2. Sampling inheritance did not work as expected, due to the fact that OTEL spans cannot differentiate between `sampled=false` (sampled to be not recorded) and `sampled=undefined` (no sampling decision yet). ## Update to `continueTrace` & trace propagation While my first instinct was to ensure that in the trace methods, if we have remote span we ignore it and look at the propagation context, this has a bunch of problems - because it means we can run out of sync, if this is set from outside, etc. So instead, I now provide a custom `continueTrace` method from `@sentry/opentelemetry` & `@sentry/node` which should be used instead of the core one in meta SDKs. This method will, in addition to updating the propagation context, _also_ create a remote span with the passed in data, and make it the active span in the callback. Then, I updated the otel start span APIs to always use that, if it exists (which was already the behavior we had), PLUS also added behavior that if there is no active span at all (not even a remote one), _then_ we look at the propagation context. ## Update to sampling inheritance Previously, we basically did the following: ```ts const sampled: Boolean | undefined = spanContext.traceFlags === TraceFlags.SAMPLED; // this will always be true or false, never undefined ``` Which means that if we create a remote span from a minimal propagation context: ```ts // This could be a generated propagation context from a scope const propagationContext = { spanId: 'xxx', traceId: 'yyy' }; const spanContext: SpanContext = { sampled: propagationContext.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE, } ``` We would later always get `sampled: false`, and inherit this decision for all downstream spans - instead of treating it as `undefined`, and going through the sampler, as we actually want it to. In order to "solve" this, I added a new trace state `SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING`, which we set if we _know_ this is actually `sampled: false`, and not just unset. Then, based on this we can interpret `sampled` as being `false` or `undefined`, respectively. This is a bit hacky but should work - it means that if we get a sampling decision from outside we'll treat it as `undefined`, which is OK I would say. Our own sampler will set this correctly so we inherit correctly as well, and our propagator does so too. --------- Co-authored-by: Lukas Stracke <lukas.stracke@sentry.io>
- Loading branch information
Showing
16 changed files
with
603 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.