11use {
22 crate :: {
33 api:: { ApiBlockChainState , NetworkId , RestError , StateTag } ,
4- history:: RequestStatus ,
4+ history:: { RequestQueryBuilder , RequestStatus , SearchField } ,
55 } ,
66 axum:: {
77 extract:: { Query , State } ,
88 Json ,
99 } ,
1010 chrono:: { DateTime , Utc } ,
11+ prometheus_client:: {
12+ encoding:: { EncodeLabelSet , EncodeLabelValue } ,
13+ metrics:: { family:: Family , histogram:: Histogram } ,
14+ registry:: Registry ,
15+ } ,
16+ std:: sync:: Arc ,
17+ tokio:: { sync:: RwLock , time:: Instant } ,
1118 utoipa:: IntoParams ,
1219} ;
1320
14- #[ derive( Debug , serde:: Serialize , serde:: Deserialize , IntoParams ) ]
21+ #[ derive( Debug ) ]
22+ pub struct ExplorerMetrics {
23+ results_latency : Family < QueryTags , Histogram > ,
24+ count_latency : Family < QueryTags , Histogram > ,
25+ }
26+
27+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , EncodeLabelSet ) ]
28+ pub struct QueryTags {
29+ search_type : Option < SearchType > ,
30+ has_network_id_filter : bool ,
31+ has_state_filter : bool ,
32+ limit : i64 ,
33+ }
34+
35+ impl < ' a > From < RequestQueryBuilder < ' a > > for QueryTags {
36+ fn from ( builder : RequestQueryBuilder < ' a > ) -> Self {
37+ QueryTags {
38+ search_type : builder. search . map ( |val| match val {
39+ SearchField :: TxHash ( _) => SearchType :: TxHash ,
40+ SearchField :: Sender ( _) => SearchType :: Sender ,
41+ SearchField :: SequenceNumber ( _) => SearchType :: SequenceNumber ,
42+ } ) ,
43+ has_network_id_filter : builder. network_id . is_some ( ) ,
44+ has_state_filter : builder. state . is_some ( ) ,
45+ limit : builder. limit ,
46+ }
47+ }
48+ }
49+
50+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , EncodeLabelValue ) ]
51+ enum SearchType {
52+ TxHash ,
53+ Sender ,
54+ SequenceNumber ,
55+ }
56+
57+ impl ExplorerMetrics {
58+ pub async fn new ( metrics_registry : Arc < RwLock < Registry > > ) -> Self {
59+ let mut guard = metrics_registry. write ( ) . await ;
60+ let sub_registry = guard. sub_registry_with_prefix ( "explorer" ) ;
61+
62+ let results_latency = Family :: < QueryTags , Histogram > :: new_with_constructor ( || {
63+ Histogram :: new (
64+ [
65+ 0.001 , 0.005 , 0.01 , 0.05 , 0.1 , 0.5 , 1.0 , 2.0 , 5.0 , 10.0 , 20.0 ,
66+ ]
67+ . into_iter ( ) ,
68+ )
69+ } ) ;
70+ sub_registry. register (
71+ "results_latency" ,
72+ "The latency of requests to the database to collect the limited results." ,
73+ results_latency. clone ( ) ,
74+ ) ;
75+
76+ let count_latency = Family :: < QueryTags , Histogram > :: new_with_constructor ( || {
77+ Histogram :: new (
78+ [
79+ 0.001 , 0.005 , 0.01 , 0.05 , 0.1 , 0.5 , 1.0 , 2.0 , 5.0 , 10.0 , 20.0 ,
80+ ]
81+ . into_iter ( ) ,
82+ )
83+ } ) ;
84+ sub_registry. register (
85+ "count_latency" ,
86+ "The latency of requests to the database to collect the total matching result count." ,
87+ count_latency. clone ( ) ,
88+ ) ;
89+
90+ Self {
91+ results_latency,
92+ count_latency,
93+ }
94+ }
95+ }
96+
97+ #[ derive( Debug , Clone , serde:: Serialize , serde:: Deserialize , IntoParams ) ]
1598#[ into_params( parameter_in=Query ) ]
1699pub struct ExplorerQueryParams {
17100 /// Only return logs that are newer or equal to this timestamp. Timestamp is in ISO 8601 format with UTC timezone.
@@ -96,7 +179,13 @@ pub async fn explorer(
96179 query = query. max_timestamp ( max_timestamp) ;
97180 }
98181
99- let ( requests, total_results) = tokio:: join!( query. execute( ) , query. count_results( ) ) ;
182+ let results_latency = & state. explorer_metrics . results_latency ;
183+ let count_latency = & state. explorer_metrics . count_latency ;
184+ let query_tags = & query. clone ( ) . into ( ) ;
185+ let ( requests, total_results) = tokio:: join!(
186+ measure_latency( results_latency, query_tags, query. execute( ) ) ,
187+ measure_latency( count_latency, query_tags, query. count_results( ) )
188+ ) ;
100189 let requests = requests. map_err ( |_| RestError :: TemporarilyUnavailable ) ?;
101190 let total_results = total_results. map_err ( |_| RestError :: TemporarilyUnavailable ) ?;
102191
@@ -105,3 +194,19 @@ pub async fn explorer(
105194 total_results,
106195 } ) )
107196}
197+
198+ async fn measure_latency < T , F > (
199+ metric : & Family < QueryTags , Histogram > ,
200+ query_tags : & QueryTags ,
201+ function : F ,
202+ ) -> T
203+ where
204+ F : std:: future:: Future < Output = T > ,
205+ {
206+ let start = Instant :: now ( ) ;
207+ let return_value = function. await ;
208+ metric
209+ . get_or_create ( query_tags)
210+ . observe ( start. elapsed ( ) . as_secs_f64 ( ) ) ;
211+ return_value
212+ }
0 commit comments