diff --git a/src/middleware/observability.ts b/src/middleware/observability.ts index c3892f1f..e303f8dc 100644 --- a/src/middleware/observability.ts +++ b/src/middleware/observability.ts @@ -34,6 +34,9 @@ import * as asyncHooks from "node:async_hooks"; import { + ATTR_HTTP_REQUEST_METHOD, + ATTR_HTTP_RESPONSE_STATUS_CODE, + ATTR_URL_PATH, METRIC_HTTP_CLIENT_REQUEST_DURATION, METRIC_HTTP_SERVER_REQUEST_DURATION, } from "@opentelemetry/semantic-conventions"; @@ -590,7 +593,6 @@ const isDev = export function logRequest( request: Request, status: number, - durationMs: number, extra?: Record, ) { const url = new URL(request.url); @@ -602,10 +604,9 @@ export function logRequest( // logger floor automatically (no need to attach manually here). const level = status >= 500 ? "error" : "info"; logger[level]("request handled", { - method: request.method, - path: url.pathname, - status, - duration_ms: Math.round(durationMs), + [ATTR_HTTP_REQUEST_METHOD]: request.method, + [ATTR_URL_PATH]: url.pathname, + [ATTR_HTTP_RESPONSE_STATUS_CODE]: status, ...extra, }); } diff --git a/src/sdk/workerEntry.ts b/src/sdk/workerEntry.ts index 2f49af02..e5fcc277 100644 --- a/src/sdk/workerEntry.ts +++ b/src/sdk/workerEntry.ts @@ -1136,10 +1136,14 @@ export function createDecoWorkerEntry( // Run app middleware (injects app state into RequestContext.bag, // runs registered middleware like VTEX cookie forwarding). const appMw = getAppMiddleware(); - if (appMw) { - return appMw(request, () => handleRequest(request, env, ctx)); - } - return handleRequest(request, env, ctx); + const response = await (appMw + ? appMw(request, () => handleRequest(request, env, ctx)) + : handleRequest(request, env, ctx)); + // Stamp the response status on the root span so the span status + // promotion in otelHttpTracer/otel.ts fires correctly — without + // this, deco.http.request spans for 5xx responses are always Unset. + setSpanAttribute("http.status_code", response.status); + return response; }, { "http.method": method, @@ -1222,7 +1226,7 @@ export function createDecoWorkerEntry( /* swallow — observability must never fail the request */ } try { - logRequest(request, finalResponse.status, durationMs, { + logRequest(request, finalResponse.status, { ...(identity.requestId ? { "request.id": identity.requestId } : {}), ...(identity.traceId ? { "trace.id": identity.traceId } : {}), });