|
1 | | -import { SpanStatusCode, trace } from "@opentelemetry/api"; |
| 1 | +import { SpanKind, SpanStatusCode, context, trace } from "@opentelemetry/api"; |
2 | 2 | import { |
3 | 3 | ATTR_HTTP_REQUEST_METHOD, |
4 | 4 | ATTR_HTTP_RESPONSE_STATUS_CODE, |
@@ -72,32 +72,52 @@ const cloudflareHandler: ExportedHandler<Env> = { |
72 | 72 | return fetchHandler(request, env, ctx); |
73 | 73 | } |
74 | 74 | const url = new URL(request.url); |
75 | | - return tracer.startActiveSpan(`http.server ${request.method}`, async (span) => { |
76 | | - span.setAttribute(ATTR_HTTP_REQUEST_METHOD, request.method); |
77 | | - span.setAttribute(ATTR_URL_FULL, request.url); |
78 | | - span.setAttribute(ATTR_URL_PATH, url.pathname); |
79 | | - span.setAttribute(ATTR_URL_SCHEME, url.protocol.replace(/:$/, "")); |
80 | | - // Adapter boundary: Cloudflare's fetch handler is a Promise-based |
81 | | - // callback and the OTel span lifecycle needs to observe both the |
82 | | - // resolved response and any thrown error before `span.end()`. Sentry's |
83 | | - // outer wrapper still captures the exception; we only mark span status. |
84 | | - // oxlint-disable-next-line executor/no-try-catch-or-throw -- adapter boundary |
85 | | - try { |
86 | | - const response = await fetchHandler(request, env, ctx); |
87 | | - span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, response.status); |
88 | | - if (response.status >= 500) { |
| 75 | + // Join the caller's W3C trace when the request carries one — the web UI |
| 76 | + // sends traceparent on every API fetch, so the browser's spans and this |
| 77 | + // request share one trace id end to end. Same parsing the DO path does |
| 78 | + // in session-durable-object.ts. |
| 79 | + const traceparentMatch = /^[0-9a-f]{2}-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/.exec( |
| 80 | + request.headers.get("traceparent") ?? "", |
| 81 | + ); |
| 82 | + const parentContext = traceparentMatch |
| 83 | + ? trace.setSpanContext(context.active(), { |
| 84 | + traceId: traceparentMatch[1]!, |
| 85 | + spanId: traceparentMatch[2]!, |
| 86 | + traceFlags: parseInt(traceparentMatch[3]!, 16), |
| 87 | + isRemote: true, |
| 88 | + }) |
| 89 | + : context.active(); |
| 90 | + return tracer.startActiveSpan( |
| 91 | + `http.server ${request.method}`, |
| 92 | + { kind: SpanKind.SERVER }, |
| 93 | + parentContext, |
| 94 | + async (span) => { |
| 95 | + span.setAttribute(ATTR_HTTP_REQUEST_METHOD, request.method); |
| 96 | + span.setAttribute(ATTR_URL_FULL, request.url); |
| 97 | + span.setAttribute(ATTR_URL_PATH, url.pathname); |
| 98 | + span.setAttribute(ATTR_URL_SCHEME, url.protocol.replace(/:$/, "")); |
| 99 | + // Adapter boundary: Cloudflare's fetch handler is a Promise-based |
| 100 | + // callback and the OTel span lifecycle needs to observe both the |
| 101 | + // resolved response and any thrown error before `span.end()`. Sentry's |
| 102 | + // outer wrapper still captures the exception; we only mark span status. |
| 103 | + // oxlint-disable-next-line executor/no-try-catch-or-throw -- adapter boundary |
| 104 | + try { |
| 105 | + const response = await fetchHandler(request, env, ctx); |
| 106 | + span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, response.status); |
| 107 | + if (response.status >= 500) { |
| 108 | + span.setStatus({ code: SpanStatusCode.ERROR }); |
| 109 | + } |
| 110 | + return response; |
| 111 | + } catch (err) { |
89 | 112 | span.setStatus({ code: SpanStatusCode.ERROR }); |
| 113 | + // oxlint-disable-next-line executor/no-try-catch-or-throw -- adapter boundary; preserve original error to Cloudflare runtime |
| 114 | + throw err; |
| 115 | + } finally { |
| 116 | + span.end(); |
| 117 | + ctx.waitUntil(flushTracerProvider()); |
90 | 118 | } |
91 | | - return response; |
92 | | - } catch (err) { |
93 | | - span.setStatus({ code: SpanStatusCode.ERROR }); |
94 | | - // oxlint-disable-next-line executor/no-try-catch-or-throw -- adapter boundary; preserve original error to Cloudflare runtime |
95 | | - throw err; |
96 | | - } finally { |
97 | | - span.end(); |
98 | | - ctx.waitUntil(flushTracerProvider()); |
99 | | - } |
100 | | - }); |
| 119 | + }, |
| 120 | + ); |
101 | 121 | }, |
102 | 122 | }; |
103 | 123 |
|
|
0 commit comments