@@ -134,6 +134,9 @@ class WorkerEntrypoint::ResponseSentTracker final: public kj::HttpService::Respo
134134 bool isSent () const {
135135 return sent;
136136 }
137+ uint getHttpResponseStatus () const {
138+ return httpResponseStatus;
139+ }
137140
138141 kj::Own<kj::AsyncOutputStream> send (uint statusCode,
139142 kj::StringPtr statusText,
@@ -142,6 +145,7 @@ class WorkerEntrypoint::ResponseSentTracker final: public kj::HttpService::Respo
142145 TRACE_EVENT (
143146 " workerd" , " WorkerEntrypoint::ResponseSentTracker::send()" , " statusCode" , statusCode);
144147 sent = true ;
148+ httpResponseStatus = statusCode;
145149 return inner.send (statusCode, statusText, headers, expectedBodySize);
146150 }
147151
@@ -152,6 +156,7 @@ class WorkerEntrypoint::ResponseSentTracker final: public kj::HttpService::Respo
152156 }
153157
154158 private:
159+ uint httpResponseStatus = 0 ;
155160 kj::HttpService::Response& inner;
156161 bool sent = false ;
157162};
@@ -255,6 +260,11 @@ kj::Promise<void> WorkerEntrypoint::request(kj::HttpMethod method,
255260 auto wrappedResponse = kj::heap<ResponseSentTracker>(response);
256261
257262 bool isActor = context.getActor () != kj::none;
263+ // HACK: Capture workerTracer directly, it's unclear how to acquire the right tracer from context
264+ // when we need it (for DOs, IoContext may point to a different WorkerTracer by the time we use
265+ // it). The tracer lives as long or longer than the IoContext (based on being co-owned
266+ // by IncomingRequest and PipelineTracer) so long enough.
267+ kj::Maybe<BaseTracer&> workerTracer;
258268
259269 KJ_IF_SOME (t, incomingRequest->getWorkerTracer ()) {
260270 kj::String cfJson;
@@ -281,6 +291,7 @@ kj::Promise<void> WorkerEntrypoint::request(kj::HttpMethod method,
281291
282292 t.setEventInfo (*incomingRequest,
283293 tracing::FetchEventInfo (method, kj::str (url), kj::mv (cfJson), kj::mv (traceHeadersArray)));
294+ workerTracer = t;
284295 }
285296
286297 auto metricsForCatch = kj::addRef (incomingRequest->getMetrics ());
@@ -313,10 +324,19 @@ kj::Promise<void> WorkerEntrypoint::request(kj::HttpMethod method,
313324 cfBlobJson, lock,
314325 lock.getExportedHandler (entrypointName, kj::mv (props), context.getActor ()), kj::mv (signal));
315326 })
316- .then ([this ](api::DeferredProxy<void > deferredProxy) {
327+ .then ([this , &context, &wrappedResponse = *wrappedResponse, workerTracer](
328+ api::DeferredProxy<void > deferredProxy) {
317329 TRACE_EVENT (" workerd" , " WorkerEntrypoint::request() deferred proxy step" ,
318330 PERFETTO_FLOW_FROM_POINTER (this ));
319331 proxyTask = kj::mv (deferredProxy.proxyTask );
332+ KJ_IF_SOME (t, workerTracer) {
333+ auto httpResponseStatus = wrappedResponse.getHttpResponseStatus ();
334+ if (httpResponseStatus != 0 ) {
335+ t.setReturn (context.now (), tracing::FetchResponseInfo (httpResponseStatus));
336+ } else {
337+ t.setReturn (context.now ());
338+ }
339+ }
320340 })
321341 .catch_ ([this , &context](kj::Exception&& exception) mutable -> kj::Promise<void > {
322342 TRACE_EVENT (" workerd" , " WorkerEntrypoint::request() catch" , PERFETTO_FLOW_FROM_POINTER (this ));
@@ -383,8 +403,8 @@ kj::Promise<void> WorkerEntrypoint::request(kj::HttpMethod method,
383403 proxyTask = kj::none;
384404 }))
385405 .catch_ ([this , wrappedResponse = kj::mv (wrappedResponse), isActor, method, url, &headers,
386- &requestBody, metrics = kj::mv (metricsForCatch)](
387- kj::Exception&& exception) mutable -> kj::Promise<void > {
406+ &requestBody, metrics = kj::mv (metricsForCatch),
407+ workerTracer]( kj::Exception&& exception) mutable -> kj::Promise<void > {
388408 // Don't return errors to end user.
389409 TRACE_EVENT (" workerd" , " WorkerEntrypoint::request() exception" ,
390410 PERFETTO_TERMINATING_FLOW_FROM_POINTER (this ));
@@ -449,7 +469,7 @@ kj::Promise<void> WorkerEntrypoint::request(kj::HttpMethod method,
449469 metrics->setFailedOpen (true );
450470 return promise.attach (kj::mv (service));
451471 });
452- return promise.catch_ ([this , wrappedResponse = kj::mv (wrappedResponse),
472+ return promise.catch_ ([this , wrappedResponse = kj::mv (wrappedResponse), workerTracer,
453473 metrics = kj::mv (metrics)](kj::Exception&& e) mutable {
454474 metrics->setFailedOpen (false );
455475 if (e.getType () != kj::Exception::Type::DISCONNECTED &&
@@ -462,6 +482,9 @@ kj::Promise<void> WorkerEntrypoint::request(kj::HttpMethod method,
462482 if (!wrappedResponse->isSent ()) {
463483 kj::HttpHeaders headers (threadContext.getHeaderTable ());
464484 wrappedResponse->send (500 , " Internal Server Error" , headers, uint64_t (0 ));
485+ KJ_IF_SOME (t, workerTracer) {
486+ t.setReturn (kj::none, tracing::FetchResponseInfo (500 ));
487+ }
465488 }
466489 });
467490 } else if (tunnelExceptions) {
@@ -485,6 +508,10 @@ kj::Promise<void> WorkerEntrypoint::request(kj::HttpMethod method,
485508 } else {
486509 wrappedResponse->send (500 , " Internal Server Error" , headers, uint64_t (0 ));
487510 }
511+ KJ_IF_SOME (t, workerTracer) {
512+ t.setReturn (
513+ kj::none, tracing::FetchResponseInfo (wrappedResponse->getHttpResponseStatus ()));
514+ }
488515 }
489516
490517 return kj::READY_NOW;
0 commit comments