1+ use std:: borrow:: Cow ;
12use std:: collections:: { BTreeMap , HashSet } ;
23use std:: error:: Error ;
34use std:: future:: Future ;
@@ -37,6 +38,7 @@ pub struct RequestSummary {
3738 pub duration_ms : AtomicU64 ,
3839 pub supergraph_identifier : AtomicU64 ,
3940 pub custom : Mutex < BTreeMap < String , sonic_rs:: Value > > ,
41+ pub message : OnceLock < Cow < ' static , str > > ,
4042}
4143
4244impl RequestSummary {
@@ -94,6 +96,11 @@ impl RequestSummary {
9496 }
9597 }
9698
99+ /// Overrides the summary log line's message. First call wins; later calls are no-ops.
100+ pub fn set_message ( & self , message : impl Into < Cow < ' static , str > > ) {
101+ let _ = self . message . set ( message. into ( ) ) ;
102+ }
103+
97104 pub fn record_subgraph ( & self , name : & str ) {
98105 self . subgraph_requests . fetch_add ( 1 , Relaxed ) ;
99106 if let Ok ( mut subgraphs) = self . involved_subgraphs . lock ( ) {
@@ -116,6 +123,7 @@ impl RequestSummary {
116123
117124 info ! (
118125 target: targets:: SUMMARY ,
126+ message = self . message. get( ) . map( Cow :: as_ref) ,
119127 client_name = self . client_name. get( ) . map( String :: as_str) ,
120128 client_version = self . client_version. get( ) . map( String :: as_str) ,
121129 operation_name = self . operation_name. get( ) . map( String :: as_str) ,
@@ -160,6 +168,10 @@ pub fn record(f: impl FnOnce(&RequestSummary)) {
160168 let _ = REQUEST_SUMMARY . try_with ( |summary| f ( summary) ) ;
161169}
162170
171+ pub fn current_summary ( ) -> Option < Arc < RequestSummary > > {
172+ REQUEST_SUMMARY . try_with ( |summary| summary. clone ( ) ) . ok ( )
173+ }
174+
163175pub fn emit ( ) {
164176 if !is_enabled ( ) {
165177 return ;
@@ -242,10 +254,15 @@ impl Drop for SummaryOnDrop {
242254 } ;
243255 summary. set_duration ( self . started_at . elapsed ( ) ) ;
244256
245- match self . request_ids . take ( ) {
246- Some ( ids) => REQUEST_IDENTIFIERS . sync_scope ( ids, || summary. emit ( ) ) ,
247- None => summary. emit ( ) ,
248- }
257+ // Re-enter both task-locals before emitting: by now (especially for responses whose
258+ // body outlives the original request future) they may no longer be ambiently scoped,
259+ // but the formatters look up `custom`/`correlations` independently via their own
260+ // `try_with` at format time, so both must be active for that lookup to succeed.
261+ let request_ids = self . request_ids . take ( ) ;
262+ REQUEST_SUMMARY . sync_scope ( summary, || match request_ids {
263+ Some ( ids) => REQUEST_IDENTIFIERS . sync_scope ( ids, emit) ,
264+ None => emit ( ) ,
265+ } ) ;
249266 }
250267}
251268
0 commit comments