Skip to content

Commit a1d0e22

Browse files
authored
Merge pull request #2761 from pyth-network/cprussin/measure-timings-for-history-queries
feat(fortuna): add prometheus metrics for history query latency
2 parents a334a22 + 12c0944 commit a1d0e22

File tree

8 files changed

+131
-35
lines changed

8 files changed

+131
-35
lines changed

apps/fortuna/Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/fortuna/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ ethabi = "18.0.0"
1919
ethers = { version = "2.0.14", features = ["ws"] }
2020
futures = { version = "0.3.28" }
2121
hex = "0.4.3"
22-
prometheus-client = { version = "0.21.2" }
22+
prometheus-client = { version = "0.23.1" }
2323
pythnet-sdk = { path = "../../pythnet/pythnet_sdk", features = ["strum"] }
2424
rand = "0.8.5"
2525
reqwest = { version = "0.11.22", features = ["json", "blocking"] }

apps/fortuna/src/api.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ pub struct ApiState {
6161

6262
/// Prometheus metrics
6363
pub metrics: Arc<ApiMetrics>,
64+
65+
pub explorer_metrics: Arc<ExplorerMetrics>,
6466
}
6567

6668
impl ApiState {
@@ -73,6 +75,8 @@ impl ApiState {
7375
http_requests: Family::default(),
7476
};
7577

78+
let explorer_metrics = Arc::new(ExplorerMetrics::new(metrics_registry.clone()).await);
79+
7680
let http_requests = metrics.http_requests.clone();
7781
metrics_registry.write().await.register(
7882
"http_requests",
@@ -83,6 +87,7 @@ impl ApiState {
8387
ApiState {
8488
chains,
8589
metrics: Arc::new(metrics),
90+
explorer_metrics,
8691
history,
8792
metrics_registry,
8893
}

apps/fortuna/src/api/explorer.rs

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,89 @@
11
use {
22
crate::{
33
api::{ApiBlockChainState, NetworkId, RestError, StateTag},
4-
history::RequestStatus,
4+
config::LATENCY_BUCKETS,
5+
history::{RequestQueryBuilder, RequestStatus, SearchField},
56
},
67
axum::{
78
extract::{Query, State},
89
Json,
910
},
1011
chrono::{DateTime, Utc},
12+
prometheus_client::{
13+
encoding::{EncodeLabelSet, EncodeLabelValue},
14+
metrics::{family::Family, histogram::Histogram},
15+
registry::Registry,
16+
},
17+
std::sync::Arc,
18+
tokio::{sync::RwLock, time::Instant},
1119
utoipa::IntoParams,
1220
};
1321

14-
#[derive(Debug, serde::Serialize, serde::Deserialize, IntoParams)]
22+
#[derive(Debug)]
23+
pub struct ExplorerMetrics {
24+
results_latency: Family<QueryTags, Histogram>,
25+
count_latency: Family<QueryTags, Histogram>,
26+
}
27+
28+
#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelSet)]
29+
pub struct QueryTags {
30+
search_type: Option<SearchType>,
31+
has_network_id_filter: bool,
32+
has_state_filter: bool,
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+
}
46+
}
47+
}
48+
49+
#[derive(Debug, Clone, PartialEq, Eq, Hash, EncodeLabelValue)]
50+
enum SearchType {
51+
TxHash,
52+
Sender,
53+
SequenceNumber,
54+
}
55+
56+
impl ExplorerMetrics {
57+
pub async fn new(metrics_registry: Arc<RwLock<Registry>>) -> Self {
58+
let mut guard = metrics_registry.write().await;
59+
let sub_registry = guard.sub_registry_with_prefix("explorer");
60+
61+
let results_latency = Family::<QueryTags, Histogram>::new_with_constructor(|| {
62+
Histogram::new(LATENCY_BUCKETS.into_iter())
63+
});
64+
sub_registry.register(
65+
"results_latency",
66+
"The latency of requests to the database to collect the limited results.",
67+
results_latency.clone(),
68+
);
69+
70+
let count_latency = Family::<QueryTags, Histogram>::new_with_constructor(|| {
71+
Histogram::new(LATENCY_BUCKETS.into_iter())
72+
});
73+
sub_registry.register(
74+
"count_latency",
75+
"The latency of requests to the database to collect the total matching result count.",
76+
count_latency.clone(),
77+
);
78+
79+
Self {
80+
results_latency,
81+
count_latency,
82+
}
83+
}
84+
}
85+
86+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, IntoParams)]
1587
#[into_params(parameter_in=Query)]
1688
pub struct ExplorerQueryParams {
1789
/// Only return logs that are newer or equal to this timestamp. Timestamp is in ISO 8601 format with UTC timezone.
@@ -96,7 +168,13 @@ pub async fn explorer(
96168
query = query.max_timestamp(max_timestamp);
97169
}
98170

99-
let (requests, total_results) = tokio::join!(query.execute(), query.count_results());
171+
let results_latency = &state.explorer_metrics.results_latency;
172+
let count_latency = &state.explorer_metrics.count_latency;
173+
let query_tags = &query.clone().into();
174+
let (requests, total_results) = tokio::join!(
175+
measure_latency(results_latency, query_tags, query.execute()),
176+
measure_latency(count_latency, query_tags, query.count_results())
177+
);
100178
let requests = requests.map_err(|_| RestError::TemporarilyUnavailable)?;
101179
let total_results = total_results.map_err(|_| RestError::TemporarilyUnavailable)?;
102180

@@ -105,3 +183,19 @@ pub async fn explorer(
105183
total_results,
106184
}))
107185
}
186+
187+
async fn measure_latency<T, F>(
188+
metric: &Family<QueryTags, Histogram>,
189+
query_tags: &QueryTags,
190+
function: F,
191+
) -> T
192+
where
193+
F: std::future::Future<Output = T>,
194+
{
195+
let start = Instant::now();
196+
let return_value = function.await;
197+
metric
198+
.get_or_create(query_tags)
199+
.observe(start.elapsed().as_secs_f64());
200+
return_value
201+
}

apps/fortuna/src/config.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use {
1111
};
1212
pub use {
1313
generate::GenerateOptions, get_request::GetRequestOptions, inspect::InspectOptions,
14-
register_provider::RegisterProviderOptions, request_randomness::RequestRandomnessOptions,
15-
run::RunOptions, setup_provider::SetupProviderOptions, withdraw_fees::WithdrawFeesOptions,
14+
prometheus_client::metrics::histogram::Histogram, register_provider::RegisterProviderOptions,
15+
request_randomness::RequestRandomnessOptions, run::RunOptions,
16+
setup_provider::SetupProviderOptions, withdraw_fees::WithdrawFeesOptions,
1617
};
1718

1819
mod generate;
@@ -367,3 +368,9 @@ impl SecretString {
367368
Ok(None)
368369
}
369370
}
371+
372+
/// This is a histogram with a bucket configuration appropriate for most things
373+
/// which measure latency to external services.
374+
pub const LATENCY_BUCKETS: [f64; 11] = [
375+
0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 20.0,
376+
];

apps/fortuna/src/eth_utils/traced_client.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::api::ChainId,
2+
crate::{api::ChainId, config::LATENCY_BUCKETS},
33
anyhow::Result,
44
axum::async_trait,
55
ethers::{
@@ -42,12 +42,7 @@ impl RpcMetrics {
4242
);
4343

4444
let latency = Family::<RpcLabel, Histogram>::new_with_constructor(|| {
45-
Histogram::new(
46-
[
47-
0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 20.0,
48-
]
49-
.into_iter(),
50-
)
45+
Histogram::new(LATENCY_BUCKETS.into_iter())
5146
});
5247
sub_registry.register(
5348
"latency",

apps/fortuna/src/history.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -345,13 +345,13 @@ impl History {
345345
#[derive(Debug, Clone)]
346346
pub struct RequestQueryBuilder<'a> {
347347
pool: &'a Pool<Sqlite>,
348-
search: Option<SearchField>,
349-
network_id: Option<i64>,
350-
state: Option<StateTag>,
351-
limit: i64,
352-
offset: i64,
353-
min_timestamp: DateTime<chrono::Utc>,
354-
max_timestamp: DateTime<chrono::Utc>,
348+
pub search: Option<SearchField>,
349+
pub network_id: Option<i64>,
350+
pub state: Option<StateTag>,
351+
pub limit: i64,
352+
pub offset: i64,
353+
pub min_timestamp: DateTime<chrono::Utc>,
354+
pub max_timestamp: DateTime<chrono::Utc>,
355355
}
356356

357357
impl<'a> RequestQueryBuilder<'a> {
@@ -503,7 +503,7 @@ pub enum RequestQueryBuilderError {
503503
}
504504

505505
#[derive(Debug, Clone)]
506-
enum SearchField {
506+
pub enum SearchField {
507507
TxHash(TxHash),
508508
Sender(Address),
509509
SequenceNumber(i64),

apps/fortuna/src/keeper/keeper_metrics.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,19 @@ impl Default for KeeperMetrics {
6969
requests_reprocessed: Family::default(),
7070
reveals: Family::default(),
7171
request_duration_ms: Family::new_with_constructor(|| {
72-
Histogram::new(
73-
vec![
74-
1000.0, 2500.0, 5000.0, 7500.0, 10000.0, 20000.0, 30000.0, 40000.0,
75-
50000.0, 60000.0, 120000.0, 180000.0, 240000.0, 300000.0, 600000.0,
76-
]
77-
.into_iter(),
78-
)
72+
Histogram::new(vec![
73+
1000.0, 2500.0, 5000.0, 7500.0, 10000.0, 20000.0, 30000.0, 40000.0, 50000.0,
74+
60000.0, 120000.0, 180000.0, 240000.0, 300000.0, 600000.0,
75+
])
7976
}),
8077
retry_count: Family::new_with_constructor(|| {
81-
Histogram::new(vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0].into_iter())
78+
Histogram::new(vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0])
8279
}),
8380
final_gas_multiplier: Family::new_with_constructor(|| {
84-
Histogram::new(
85-
vec![100.0, 125.0, 150.0, 200.0, 300.0, 400.0, 500.0, 600.0].into_iter(),
86-
)
81+
Histogram::new(vec![100.0, 125.0, 150.0, 200.0, 300.0, 400.0, 500.0, 600.0])
8782
}),
8883
final_fee_multiplier: Family::new_with_constructor(|| {
89-
Histogram::new(vec![100.0, 110.0, 120.0, 140.0, 160.0, 180.0, 200.0].into_iter())
84+
Histogram::new(vec![100.0, 110.0, 120.0, 140.0, 160.0, 180.0, 200.0])
9085
}),
9186
gas_price_estimate: Family::default(),
9287
highest_revealed_sequence_number: Family::default(),

0 commit comments

Comments
 (0)