@@ -8,48 +8,51 @@ use conduit::{header, RequestExt, StatusCode};
88
99use crate :: middleware:: normalize_path:: OriginalPath ;
1010use crate :: middleware:: response_timing:: ResponseTime ;
11+ use std:: cell:: RefCell ;
1112use std:: fmt:: { self , Display , Formatter } ;
1213
1314const SLOW_REQUEST_THRESHOLD_MS : u64 = 1000 ;
1415
16+ // A thread local is used instead of a request extension to avoid the need to pass the request
17+ // object everywhere in the codebase. When migrating to async this will need to be moved to an
18+ // async-equivalent, as thread locals misbehave in async contexes.
19+ thread_local ! {
20+ static CUSTOM_METADATA : RefCell <Vec <( & ' static str , String ) >> = RefCell :: new( Vec :: new( ) ) ;
21+ }
22+
1523#[ derive( Default ) ]
1624pub ( super ) struct LogRequests ( ) ;
1725
1826impl Middleware for LogRequests {
27+ fn before ( & self , _: & mut dyn RequestExt ) -> BeforeResult {
28+ // Remove any metadata set by the previous task before processing any new request.
29+ CUSTOM_METADATA . with ( |metadata| metadata. borrow_mut ( ) . clear ( ) ) ;
30+
31+ Ok ( ( ) )
32+ }
33+
1934 fn after ( & self , req : & mut dyn RequestExt , res : AfterResult ) -> AfterResult {
2035 println ! ( "{}" , RequestLine { req, res: & res } ) ;
2136
2237 res
2338 }
2439}
2540
26- struct CustomMetadata {
27- entries : Vec < ( & ' static str , String ) > ,
28- }
29-
30- pub fn add_custom_metadata < V : Display > ( req : & mut dyn RequestExt , key : & ' static str , value : V ) {
31- if let Some ( metadata) = req. mut_extensions ( ) . get_mut :: < CustomMetadata > ( ) {
32- metadata. entries . push ( ( key, value. to_string ( ) ) ) ;
33- } else {
34- let mut metadata = CustomMetadata {
35- entries : Vec :: new ( ) ,
36- } ;
37- metadata. entries . push ( ( key, value. to_string ( ) ) ) ;
38- req. mut_extensions ( ) . insert ( metadata) ;
39- }
40-
41+ pub fn add_custom_metadata < V : Display > ( key : & ' static str , value : V ) {
42+ CUSTOM_METADATA . with ( |metadata| metadata. borrow_mut ( ) . push ( ( key, value. to_string ( ) ) ) ) ;
4143 sentry:: configure_scope ( |scope| scope. set_extra ( key, value. to_string ( ) . into ( ) ) ) ;
4244}
4345
4446#[ cfg( test) ]
45- pub ( crate ) fn get_log_message ( req : & dyn RequestExt , key : & ' static str ) -> String {
46- // Unwrap shouldn't panic as no other code has access to the private struct to remove it
47- for ( k, v) in & req. extensions ( ) . get :: < CustomMetadata > ( ) . unwrap ( ) . entries {
48- if key == * k {
49- return v. clone ( ) ;
47+ pub ( crate ) fn get_log_message ( key : & ' static str ) -> String {
48+ CUSTOM_METADATA . with ( |metadata| {
49+ for ( k, v) in & * metadata. borrow ( ) {
50+ if key == * k {
51+ return v. clone ( ) ;
52+ }
5053 }
51- }
52- panic ! ( "expected log message for {} not found" , key ) ;
54+ panic ! ( "expected log message for {} not found" , key ) ;
55+ } )
5356}
5457
5558struct RequestLine < ' r > {
@@ -95,11 +98,12 @@ impl Display for RequestLine<'_> {
9598 line. add_field ( "status" , status. as_str ( ) ) ?;
9699 line. add_quoted_field ( "user_agent" , request_header ( self . req , header:: USER_AGENT ) ) ?;
97100
98- if let Some ( metadata ) = self . req . extensions ( ) . get :: < CustomMetadata > ( ) {
99- for ( key, value) in & metadata. entries {
101+ CUSTOM_METADATA . with ( |metadata| {
102+ for ( key, value) in & * metadata. borrow ( ) {
100103 line. add_quoted_field ( key, value) ?;
101104 }
102- }
105+ fmt:: Result :: Ok ( ( ) )
106+ } ) ?;
103107
104108 if let Err ( err) = self . res {
105109 line. add_quoted_field ( "error" , err) ?;
0 commit comments