-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
fix(node): Fix virtual parent span ID handling & update create-next-app E2E test #12368
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
Conversation
dev-packages/e2e-tests/test-applications/create-next-app/tests/server-transactions.test.ts
Outdated
Show resolved
Hide resolved
2ff28ff
to
136e30e
Compare
136e30e
to
0532f16
Compare
@@ -14,7 +14,7 @@ | |||
"test:prepare": "ts-node prepare.ts", | |||
"test:validate": "run-s test:validate-configuration test:validate-test-app-setups", | |||
"clean": "rimraf tmp node_modules pnpm-lock.yaml && yarn clean:test-applications", | |||
"clean:test-applications": "rimraf test-applications/**/{node_modules,dist,build,.next,.sveltekit,pnpm-lock.yaml} .last-run.json" | |||
"clean:test-applications": "rimraf test-applications/**/{node_modules,dist,build,.next,.sveltekit,pnpm-lock.yaml} .last-run.json && pnpm store prune" |
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.
Noticed that without this, running tests locally would often get cached node_modules :(
traceId: uuid4(), | ||
spanId: uuid4().substring(16), | ||
}); | ||
return startNewTrace(() => { |
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 new API does the same thing, so we can leverage this now instead.
@@ -81,8 +81,10 @@ export function wrapApiHandlerWithSentry(apiHandler: NextApiHandler, parameteriz | |||
// eslint-disable-next-line @typescript-eslint/unbound-method | |||
res.end = new Proxy(res.end, { | |||
apply(target, thisArg, argArray) { | |||
setHttpStatus(span, res.statusCode); | |||
span.end(); | |||
if (span.isRecording()) { |
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 noticed this in tests, we sometimes seemed to double-end spans, so guarding against this here.
size-limit report 📦
|
OK, another iteration on this! Turns out setting an invalid spanID on a span will make OTEL ignore all of this, including the trace ID, and instead will create a new trace ID for a new span, which is not what we want. So we can't use this... So instead, I now adjusted the already existing code to keep the incoming |
const traceStateBase = parentSpanId | ||
? new TraceState().set(SENTRY_TRACE_STATE_PARENT_SPAN_ID, parentSpanId) | ||
: new TraceState(); | ||
// We _always_ set the parent span ID, because we can infer from the existence of this if we should use this |
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.
m: This comment is a bit confusing to read because of all of this
. Can we replace this
with actual objects? 😄
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 updated the comment!
…pp E2E test (#12368) This started out as updating the create-next-app test to not send to sentry anymore, but instead check payloads. However, while doing this, I noticed some inconsistencies, mostly that there was a weird `parent_span_id` in api route transactions/errors where there should be none. **EDIT** OK, another iteration on this! Turns out setting an invalid spanID on a span will make OTEL ignore all of this, including the trace ID, and instead will create a new trace ID for a new span, which is not what we want. So we can't use this... So instead, I now adjusted the already existing code to keep the incoming parentSpanId on the trace state. The major change I did is ensure we set this even if it is empty (it is set to an empty string then). This way, we can identify if this has been set, and if it has, use this as source of truth. And we can fall back to use the regular parentSpanId if this is not set (for whatever reason). **ORIGINAL** So I set out to figure out what was happening there, and the problem was that when continuing a virtual trace, we would construct a parent spanContext like this: ```js const spanContext: SpanContext = { traceId: propagationContext.traceId, spanId: propagationContext.parentSpanId || propagationContext.spanId, isRemote: true, traceFlags: propagationContext.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE, traceState, }; ``` The problematic line is this: `spanId: propagationContext.parentSpanId || propagationContext.spanId,`. Since `spanId` is required on the SpanContext, we had to set it to something, but `propagationContext.parentSpanId` is by design often undefined. With this behavior, we always set this to the random span ID we have on the propagationContext, and picked this up downstream. this now became: ```js const spanContext: SpanContext = { traceId: propagationContext.traceId, spanId: propagationContext.parentSpanId || INVALID_SPANID, isRemote: true, traceFlags: propagationContext.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE, traceState, }; ``` Plus a check further down: ```js const traceState = makeTraceState({ dsc, parentSpanId: spanId !== INVALID_SPANID ? spanId : undefined, sampled, }); ``` (Note, `INVALID_SPANID` is a constant exported from OTEL, which is basically `0000....`). I'll investigate in a follow up if it would make sense to always use this for the propagation context, instead of a random one today, plus ensuring that we always filter this out before we send, or something like this 🤔 Part of #11910
This started out as updating the create-next-app test to not send to sentry anymore, but instead check payloads.
However, while doing this, I noticed some inconsistencies, mostly that there was a weird
parent_span_id
in api route transactions/errors where there should be none.EDIT
OK, another iteration on this!
Turns out setting an invalid spanID on a span will make OTEL ignore all of this, including the trace ID, and instead will create a new trace ID for a new span, which is not what we want. So we can't use this...
So instead, I now adjusted the already existing code to keep the incoming parentSpanId on the trace state. The major change I did is ensure we set this even if it is empty (it is set to an empty string then). This way, we can identify if this has been set, and if it has, use this as source of truth. And we can fall back to use the regular parentSpanId if this is not set (for whatever reason).
ORIGINAL
So I set out to figure out what was happening there, and the problem was that when continuing a virtual trace, we would construct a parent spanContext like this:
The problematic line is this:
spanId: propagationContext.parentSpanId || propagationContext.spanId,
. SincespanId
is required on the SpanContext, we had to set it to something, butpropagationContext.parentSpanId
is by design often undefined. With this behavior, we always set this to the random span ID we have on the propagationContext, and picked this up downstream.this now became:
Plus a check further down:
(Note,
INVALID_SPANID
is a constant exported from OTEL, which is basically0000....
).I'll investigate in a follow up if it would make sense to always use this for the propagation context, instead of a random one today, plus ensuring that we always filter this out before we send, or something like this 🤔
Part of #11910