6
6
//! All the API routes have the `/api` prefix and the version number as the
7
7
//! first path segment. For example: `/api/v1/torrents`.
8
8
use std:: sync:: Arc ;
9
+ use std:: time:: Duration ;
9
10
11
+ use axum:: http:: { HeaderName , HeaderValue } ;
12
+ use axum:: response:: Response ;
10
13
use axum:: routing:: get;
11
14
use axum:: { middleware, Router } ;
15
+ use hyper:: Request ;
12
16
use torrust_tracker_configuration:: AccessTokens ;
13
17
use tower_http:: compression:: CompressionLayer ;
18
+ use tower_http:: propagate_header:: PropagateHeaderLayer ;
19
+ use tower_http:: request_id:: { MakeRequestId , RequestId , SetRequestIdLayer } ;
20
+ use tower_http:: trace:: { DefaultMakeSpan , TraceLayer } ;
21
+ use tracing:: { Level , Span } ;
22
+ use uuid:: Uuid ;
14
23
15
24
use super :: v1;
16
25
use super :: v1:: context:: health_check:: handlers:: health_check_handler;
@@ -32,4 +41,47 @@ pub fn router(tracker: Arc<Tracker>, access_tokens: Arc<AccessTokens>) -> Router
32
41
. layer ( middleware:: from_fn_with_state ( state, v1:: middlewares:: auth:: auth) )
33
42
. route ( & format ! ( "{api_url_prefix}/health_check" ) , get ( health_check_handler) )
34
43
. layer ( CompressionLayer :: new ( ) )
44
+ . layer ( SetRequestIdLayer :: x_request_id ( RequestIdGenerator ) )
45
+ . layer ( PropagateHeaderLayer :: new ( HeaderName :: from_static ( "x-request-id" ) ) )
46
+ . layer (
47
+ TraceLayer :: new_for_http ( )
48
+ . make_span_with ( DefaultMakeSpan :: new ( ) . level ( Level :: INFO ) )
49
+ . on_request ( |request : & Request < axum:: body:: Body > , _span : & Span | {
50
+ let method = request. method ( ) . to_string ( ) ;
51
+ let uri = request. uri ( ) . to_string ( ) ;
52
+ let request_id = request
53
+ . headers ( )
54
+ . get ( "x-request-id" )
55
+ . map ( |v| v. to_str ( ) . unwrap_or_default ( ) )
56
+ . unwrap_or_default ( ) ;
57
+
58
+ tracing:: span!(
59
+ target: "API" ,
60
+ tracing:: Level :: INFO , "request" , method = %method, uri = %uri, request_id = %request_id) ;
61
+ } )
62
+ . on_response ( |response : & Response , latency : Duration , _span : & Span | {
63
+ let status_code = response. status ( ) ;
64
+ let request_id = response
65
+ . headers ( )
66
+ . get ( "x-request-id" )
67
+ . map ( |v| v. to_str ( ) . unwrap_or_default ( ) )
68
+ . unwrap_or_default ( ) ;
69
+ let latency_ms = latency. as_millis ( ) ;
70
+
71
+ tracing:: span!(
72
+ target: "API" ,
73
+ tracing:: Level :: INFO , "response" , latency = %latency_ms, status = %status_code, request_id = %request_id) ;
74
+ } ) ,
75
+ )
76
+ . layer ( SetRequestIdLayer :: x_request_id ( RequestIdGenerator ) )
77
+ }
78
+
79
+ #[ derive( Clone , Default ) ]
80
+ struct RequestIdGenerator ;
81
+
82
+ impl MakeRequestId for RequestIdGenerator {
83
+ fn make_request_id < B > ( & mut self , _request : & Request < B > ) -> Option < RequestId > {
84
+ let id = HeaderValue :: from_str ( & Uuid :: new_v4 ( ) . to_string ( ) ) . expect ( "UUID is a valid HTTP header value" ) ;
85
+ Some ( RequestId :: new ( id) )
86
+ }
35
87
}
0 commit comments