1- use std:: sync:: Arc ;
1+ use std:: {
2+ sync:: Arc ,
3+ time:: { Duration , Instant } ,
4+ } ;
25
36use axum:: {
47 Extension ,
@@ -11,17 +14,57 @@ use bytes::Bytes;
1114use derive_new:: new;
1215use http:: HeaderValue ;
1316use ic_bn_lib:: {
14- http:: { ConnInfo , extract_authority, headers:: X_REAL_IP , http_method, http_version} ,
17+ http:: {
18+ ConnInfo , extract_authority, headers:: X_REAL_IP , http_method, http_version, server:: TlsInfo ,
19+ } ,
1520 vector:: client:: Vector ,
1621} ;
22+ use prometheus:: {
23+ HistogramVec , IntCounterVec , Registry , register_histogram_vec_with_registry,
24+ register_int_counter_vec_with_registry,
25+ } ;
1726use serde_json:: json;
1827use tracing:: info;
1928
2029use crate :: { backend:: Backend , middleware:: request_id:: RequestId } ;
2130
31+ pub const HTTP_DURATION_BUCKETS : & [ f64 ] = & [ 0.05 , 0.2 , 1.0 , 2.0 ] ;
32+
33+ #[ derive( Clone ) ]
34+ pub struct Metrics {
35+ pub requests : IntCounterVec ,
36+ pub duration : HistogramVec ,
37+ }
38+
39+ impl Metrics {
40+ pub fn new ( registry : & Registry ) -> Self {
41+ const LABELS_HTTP : & [ & str ] = & [ "tls" , "method" , "http" , "status" , "backend" ] ;
42+
43+ Self {
44+ requests : register_int_counter_vec_with_registry ! (
45+ format!( "http_requests" ) ,
46+ format!( "Counts occurrences of requests" ) ,
47+ LABELS_HTTP ,
48+ registry
49+ )
50+ . unwrap ( ) ,
51+
52+ duration : register_histogram_vec_with_registry ! (
53+ format!( "http_requests_duration_sec" ) ,
54+ format!( "Records the duration of request processing in seconds" ) ,
55+ LABELS_HTTP ,
56+ HTTP_DURATION_BUCKETS . to_vec( ) ,
57+ registry
58+ )
59+ . unwrap ( ) ,
60+ }
61+ }
62+ }
63+
2264#[ derive( new) ]
2365pub struct MetricsState {
2466 vector : Option < Arc < Vector > > ,
67+ metrics : Metrics ,
2568 log_requests : bool ,
2669}
2770
@@ -31,6 +74,7 @@ pub async fn middleware(
3174 mut request : Request ,
3275 next : Next ,
3376) -> Response {
77+ let tls_info = request. extensions ( ) . get :: < Arc < TlsInfo > > ( ) . cloned ( ) ;
3478 let method = http_method ( request. method ( ) ) ;
3579 let authority = extract_authority ( & request) . unwrap_or_default ( ) . to_string ( ) ;
3680 let http_version = http_version ( request. version ( ) ) ;
@@ -49,7 +93,11 @@ pub async fn middleware(
4993 HeaderValue :: from_maybe_shared ( Bytes :: from ( remote_addr. clone ( ) ) ) . unwrap ( ) ,
5094 ) ;
5195
96+ // Execute the request
97+ let start = Instant :: now ( ) ;
5298 let mut response = next. run ( request) . await ;
99+ let duration = start. elapsed ( ) . as_secs_f64 ( ) ;
100+
53101 let backend = response
54102 . extensions_mut ( )
55103 . remove :: < Arc < Backend > > ( )
@@ -61,25 +109,51 @@ pub async fn middleware(
61109 . exact ( )
62110 . map ( |x| x as i64 )
63111 . unwrap_or ( -1 ) ;
64-
65112 let request_id = response
66113 . extensions_mut ( )
67114 . remove :: < RequestId > ( )
68115 . map ( |x| x. to_string ( ) )
69116 . unwrap_or_default ( ) ;
70-
71117 let status = response. status ( ) ;
72118
119+ let ( tls_version, tls_cipher, tls_handshake) =
120+ tls_info. as_ref ( ) . map_or ( ( "" , "" , Duration :: ZERO ) , |x| {
121+ (
122+ x. protocol . as_str ( ) . unwrap ( ) ,
123+ x. cipher . as_str ( ) . unwrap ( ) ,
124+ x. handshake_dur ,
125+ )
126+ } ) ;
127+
128+ let labels = & [
129+ tls_version,
130+ method,
131+ http_version,
132+ status. as_str ( ) ,
133+ backend. as_str ( ) ,
134+ ] ;
135+
136+ state. metrics . requests . with_label_values ( labels) . inc ( ) ;
137+ state
138+ . metrics
139+ . duration
140+ . with_label_values ( labels)
141+ . observe ( duration) ;
142+
73143 if state. log_requests {
74144 info ! (
75145 request_id,
146+ tls_version,
147+ tls_cipher,
148+ tls_handshake = tls_handshake. as_secs_f64( ) ,
76149 http_version,
77150 authority,
78151 method,
79152 path,
80153 query,
81154 remote_addr,
82155 status = status. as_str( ) ,
156+ duration,
83157 backend,
84158 request_size,
85159 response_size,
@@ -89,12 +163,16 @@ pub async fn middleware(
89163 if let Some ( v) = & state. vector {
90164 let event = json ! ( {
91165 "request_id" : request_id,
166+ "tls_version" : tls_version,
167+ "tls_cipher" : tls_cipher,
168+ "tls_handshake" : tls_handshake. as_secs_f64( ) ,
92169 "http_version" : http_version,
93170 "authority" : authority,
94171 "method" : method,
95172 "path" : path,
96173 "query" : query,
97174 "status" : status. as_str( ) ,
175+ "duration" : duration,
98176 "backend" : backend,
99177 "remote_addr" : remote_addr,
100178 "request_size" : request_size,
0 commit comments