Skip to content

Commit 2b77e8e

Browse files
committed
expand metrics
1 parent cadefca commit 2b77e8e

File tree

13 files changed

+134
-68
lines changed

13 files changed

+134
-68
lines changed

crates/pbs/src/constants.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub(crate) const STATUS_ENDPOINT_TAG: &str = "status";
2+
pub(crate) const REGISTER_VALIDATOR_ENDPOINT_TAG: &str = "register_validator";
3+
pub(crate) const SUBMIT_BLINDED_BLOCK_ENDPOINT_TAG: &str = "submit_blinded_block";
4+
pub(crate) const GET_HEADER_ENDPOINT_TAG: &str = "get_header";

crates/pbs/src/error.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
use alloy::primitives::{B256, U256};
2-
use alloy::rpc::types::beacon::BlsPublicKey;
1+
use alloy::{
2+
primitives::{B256, U256},
3+
rpc::types::beacon::BlsPublicKey,
4+
};
35
use axum::{http::StatusCode, response::IntoResponse};
46
use thiserror::Error;
57

@@ -10,19 +12,26 @@ pub enum PbsClientError {
1012
NoPayload,
1113
}
1214

13-
impl IntoResponse for PbsClientError {
14-
fn into_response(self) -> axum::response::Response {
15+
impl PbsClientError {
16+
pub fn status_code(&self) -> StatusCode {
1517
match self {
16-
PbsClientError::NoResponse => {
17-
(StatusCode::SERVICE_UNAVAILABLE, "no response from relays").into_response()
18-
}
19-
PbsClientError::NoPayload => {
20-
(StatusCode::BAD_GATEWAY, "no payload from relays").into_response()
21-
}
18+
PbsClientError::NoResponse => StatusCode::SERVICE_UNAVAILABLE,
19+
PbsClientError::NoPayload => StatusCode::BAD_GATEWAY,
2220
}
2321
}
2422
}
2523

24+
impl IntoResponse for PbsClientError {
25+
fn into_response(self) -> axum::response::Response {
26+
let msg = match self {
27+
PbsClientError::NoResponse => "no response from relays",
28+
PbsClientError::NoPayload => "no payload from relays",
29+
};
30+
31+
(self.status_code(), msg).into_response()
32+
}
33+
}
34+
2635
#[derive(Debug, Error)]
2736
pub enum PbsError {
2837
#[error("axum error: {0}")]

crates/pbs/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// implements https://github.com/ethereum/builder-specs and multiplexes to multiple builderAPI compatible clients (ie MEV Boost relays)
22

33
mod boost;
4+
mod constants;
45
mod error;
56
mod metrics;
67
mod mev_boost;

crates/pbs/src/metrics.rs

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,43 @@
1+
//! Metrics for PBS module
2+
//! We collect two types of metrics within the PBS module:
3+
//! - what PBS receives from relays
4+
//! - what PBS returns to the beacon node
5+
16
use lazy_static::lazy_static;
2-
use prometheus::{histogram_opts, opts, HistogramVec, IntCounterVec, Registry};
7+
use prometheus::{
8+
register_histogram_vec_with_registry, register_int_counter_vec_with_registry, HistogramVec,
9+
IntCounterVec, Registry,
10+
};
311

412
lazy_static! {
5-
pub static ref PBS_METRICS_REGISTRY: prometheus::Registry =
13+
pub static ref PBS_METRICS_REGISTRY: Registry =
614
Registry::new_custom(Some("cb_pbs".to_string()), None).unwrap();
7-
pub static ref REQUESTS_RECEIVED: IntCounterVec =
8-
IntCounterVec::new(opts!("requests_received", "Number of requests received"), &[
9-
"endpoint",
10-
])
11-
.unwrap();
12-
pub static ref RELAY_RESPONSES: IntCounterVec =
13-
IntCounterVec::new(opts!("relay_response", "Number of requests received"), &[
14-
"code", "endpoint", "relay_id"
15-
])
16-
.unwrap();
17-
pub static ref RELAY_RESPONSE_TIME: HistogramVec =
18-
HistogramVec::new(histogram_opts!("relay_response_time", "Relay response times"), &[
19-
"endpoint", "relay_id"
20-
])
21-
.unwrap();
22-
}
2315

24-
// TODO: this can be done with the macros, need to fix the types
25-
pub fn register_default_metrics() {
26-
PBS_METRICS_REGISTRY.register(Box::new(REQUESTS_RECEIVED.clone())).expect("failed to register");
16+
// FROM RELAYS
17+
/// Status code received by relay by endpoint
18+
pub static ref RELAY_STATUS_CODE: IntCounterVec = register_int_counter_vec_with_registry!(
19+
"relay_status_code",
20+
"HTTP status code received by relay",
21+
&["http_status_code", "endpoint", "relay_id"],
22+
PBS_METRICS_REGISTRY
23+
)
24+
.unwrap();
2725

28-
PBS_METRICS_REGISTRY.register(Box::new(RELAY_RESPONSES.clone())).expect("failed to register");
26+
/// Latency by relay by endpoint
27+
pub static ref RELAY_LATENCY: HistogramVec = register_histogram_vec_with_registry!(
28+
"relay_latency",
29+
"HTTP latency by relay",
30+
&["endpoint", "relay_id"],
31+
PBS_METRICS_REGISTRY
32+
)
33+
.unwrap();
2934

30-
PBS_METRICS_REGISTRY
31-
.register(Box::new(RELAY_RESPONSE_TIME.clone()))
32-
.expect("failed to register");
35+
// TO BEACON NODE
36+
/// Status code returned to beacon node by endpoint
37+
pub static ref BEACON_NODE_STATUS: IntCounterVec = register_int_counter_vec_with_registry!(
38+
"beacon_node_status_code",
39+
"HTTP status code returned to beacon node",
40+
&["http_status_code", "endpoint"],
41+
PBS_METRICS_REGISTRY
42+
).unwrap();
3343
}

crates/pbs/src/mev_boost/get_header.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use std::{sync::Arc, time::Duration};
22

3-
use alloy::primitives::{B256, U256};
4-
use alloy::rpc::types::beacon::BlsPublicKey;
3+
use alloy::{
4+
primitives::{B256, U256},
5+
rpc::types::beacon::BlsPublicKey,
6+
};
57
use axum::http::{HeaderMap, HeaderValue};
68
use cb_common::{
79
config::PbsConfig,
@@ -15,8 +17,9 @@ use reqwest::{header::USER_AGENT, StatusCode};
1517
use tracing::{debug, error};
1618

1719
use crate::{
20+
constants::GET_HEADER_ENDPOINT_TAG,
1821
error::{PbsError, ValidationError},
19-
metrics::{RELAY_RESPONSES, RELAY_RESPONSE_TIME},
22+
metrics::{RELAY_LATENCY, RELAY_STATUS_CODE},
2023
state::{BuilderApiState, PbsState},
2124
types::{SignedExecutionPayloadHeader, EMPTY_TX_ROOT_HASH},
2225
GetHeaderParams, GetHeaderReponse,
@@ -84,7 +87,8 @@ async fn send_get_header(
8487
) -> Result<Option<GetHeaderReponse>, PbsError> {
8588
let url = relay.get_header_url(slot, parent_hash, validator_pubkey);
8689

87-
let timer = RELAY_RESPONSE_TIME.with_label_values(&["get_header", &relay.id]).start_timer();
90+
let timer =
91+
RELAY_LATENCY.with_label_values(&[GET_HEADER_ENDPOINT_TAG, &relay.id]).start_timer();
8892
let res = client
8993
.get(url)
9094
.timeout(Duration::from_millis(config.timeout_get_header_ms))
@@ -94,7 +98,9 @@ async fn send_get_header(
9498
timer.observe_duration();
9599

96100
let status = res.status();
97-
RELAY_RESPONSES.with_label_values(&[&status.to_string(), "get_header", &relay.id]).inc();
101+
RELAY_STATUS_CODE
102+
.with_label_values(&[status.as_str(), GET_HEADER_ENDPOINT_TAG, &relay.id])
103+
.inc();
98104

99105
let response_bytes = res.bytes().await?;
100106
if !status.is_success() {
@@ -184,8 +190,10 @@ fn validate_header(
184190

185191
#[cfg(test)]
186192
mod tests {
187-
use alloy::primitives::{B256, U256};
188-
use alloy::rpc::types::beacon::BlsPublicKey;
193+
use alloy::{
194+
primitives::{B256, U256},
195+
rpc::types::beacon::BlsPublicKey,
196+
};
189197
use blst::min_pk;
190198
use cb_common::{pbs::RelayEntry, signature::sign_builder_message, types::Chain};
191199

crates/pbs/src/mev_boost/register_validator.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use reqwest::header::USER_AGENT;
1111
use tracing::error;
1212

1313
use crate::{
14+
constants::REGISTER_VALIDATOR_ENDPOINT_TAG,
1415
error::PbsError,
15-
metrics::{RELAY_RESPONSES, RELAY_RESPONSE_TIME},
16+
metrics::{RELAY_LATENCY, RELAY_STATUS_CODE},
1617
state::{BuilderApiState, PbsState},
1718
};
1819

@@ -62,8 +63,9 @@ async fn send_register_validator(
6263
) -> Result<(), PbsError> {
6364
let url = relay.register_validator_url();
6465

65-
let timer =
66-
RELAY_RESPONSE_TIME.with_label_values(&["register_validator", &relay.id]).start_timer();
66+
let timer = RELAY_LATENCY
67+
.with_label_values(&[REGISTER_VALIDATOR_ENDPOINT_TAG, &relay.id])
68+
.start_timer();
6769
let res = client
6870
.post(url)
6971
.timeout(Duration::from_millis(timeout_ms))
@@ -76,7 +78,9 @@ async fn send_register_validator(
7678
// TODO: send to relay monitor
7779

7880
let status = res.status();
79-
RELAY_RESPONSES.with_label_values(&[&status.to_string(), "get_header", &relay.id]).inc();
81+
RELAY_STATUS_CODE
82+
.with_label_values(&[status.as_str(), REGISTER_VALIDATOR_ENDPOINT_TAG, &relay.id])
83+
.inc();
8084

8185
let response_bytes = res.bytes().await?;
8286
if !status.is_success() {

crates/pbs/src/mev_boost/status.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ use futures::future::select_ok;
66
use reqwest::header::USER_AGENT;
77

88
use crate::{
9+
constants::STATUS_ENDPOINT_TAG,
910
error::PbsError,
10-
metrics::{RELAY_RESPONSES, RELAY_RESPONSE_TIME},
11+
metrics::{RELAY_LATENCY, RELAY_STATUS_CODE},
1112
state::{BuilderApiState, PbsState},
1213
};
1314

1415
/// Implements https://ethereum.github.io/builder-specs/#/Builder/status
15-
/// Broadcasts a status check to all relays and returns 200 if at least one relay returns 200
16+
/// Broadcasts a status check to all relays and returns 200 if at least one
17+
/// relay returns 200
1618
pub async fn get_status<S: BuilderApiState>(
1719
req_headers: HeaderMap,
1820
state: PbsState<S>,
@@ -54,12 +56,12 @@ async fn send_relay_check(
5456
) -> Result<(), PbsError> {
5557
let url = relay.get_status_url();
5658

57-
let timer = RELAY_RESPONSE_TIME.with_label_values(&["get_status", &relay.id]).start_timer();
59+
let timer = RELAY_LATENCY.with_label_values(&[STATUS_ENDPOINT_TAG, &relay.id]).start_timer();
5860
let res = client.get(url).timeout(Duration::from_secs(30)).headers(headers).send().await?;
5961
timer.observe_duration();
6062

6163
let status = res.status();
62-
RELAY_RESPONSES.with_label_values(&[&status.to_string(), "get_status", &relay.id]).inc();
64+
RELAY_STATUS_CODE.with_label_values(&[status.as_str(), STATUS_ENDPOINT_TAG, &relay.id]).inc();
6365

6466
let response_bytes = res.bytes().await?;
6567
if !status.is_success() {

crates/pbs/src/mev_boost/submit_block.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use reqwest::header::USER_AGENT;
1111
use tracing::warn;
1212

1313
use crate::{
14+
constants::SUBMIT_BLINDED_BLOCK_ENDPOINT_TAG,
1415
error::{PbsError, ValidationError},
15-
metrics::{RELAY_RESPONSES, RELAY_RESPONSE_TIME},
16+
metrics::{RELAY_LATENCY, RELAY_STATUS_CODE},
1617
state::{BuilderApiState, PbsState},
1718
types::{SignedBlindedBeaconBlock, SubmitBlindedBlockResponse},
1819
};
@@ -63,7 +64,8 @@ pub async fn submit_block<S: BuilderApiState>(
6364
}
6465
}
6566

66-
// submits blinded signed block and expects the execution payload + blobs bundle back
67+
// submits blinded signed block and expects the execution payload + blobs bundle
68+
// back
6769
async fn send_submit_block(
6870
headers: HeaderMap,
6971
relay: RelayEntry,
@@ -73,7 +75,9 @@ async fn send_submit_block(
7375
) -> Result<SubmitBlindedBlockResponse, PbsError> {
7476
let url = relay.submit_block_url();
7577

76-
let timer = RELAY_RESPONSE_TIME.with_label_values(&["submit_block", &relay.id]).start_timer();
78+
let timer = RELAY_LATENCY
79+
.with_label_values(&[SUBMIT_BLINDED_BLOCK_ENDPOINT_TAG, &relay.id])
80+
.start_timer();
7781
let res = client
7882
.post(url)
7983
.timeout(Duration::from_millis(config.timeout_get_payload_ms))
@@ -84,7 +88,9 @@ async fn send_submit_block(
8488
timer.observe_duration();
8589

8690
let status = res.status();
87-
RELAY_RESPONSES.with_label_values(&[&status.to_string(), "submit_block", &relay.id]).inc();
91+
RELAY_STATUS_CODE
92+
.with_label_values(&[status.as_str(), SUBMIT_BLINDED_BLOCK_ENDPOINT_TAG, &relay.id])
93+
.inc();
8894

8995
let response_bytes = res.bytes().await?;
9096
if !status.is_success() {

crates/pbs/src/routes/get_header.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ use uuid::Uuid;
1010

1111
use crate::{
1212
boost::BuilderApi,
13+
constants::GET_HEADER_ENDPOINT_TAG,
1314
error::PbsClientError,
14-
metrics::REQUESTS_RECEIVED,
15+
metrics::BEACON_NODE_STATUS,
1516
state::{BuilderApiState, PbsState},
1617
BuilderEvent, GetHeaderParams,
1718
};
@@ -21,7 +22,6 @@ pub async fn handle_get_header<S: BuilderApiState, T: BuilderApi<S>>(
2122
req_headers: HeaderMap,
2223
Path(params): Path<GetHeaderParams>,
2324
) -> Result<impl IntoResponse, PbsClientError> {
24-
REQUESTS_RECEIVED.with_label_values(&["get_header"]).inc();
2525
state.publish_event(BuilderEvent::GetHeaderRequest(params));
2626

2727
let req_id = Uuid::new_v4();
@@ -37,16 +37,22 @@ pub async fn handle_get_header<S: BuilderApiState, T: BuilderApi<S>>(
3737

3838
if let Some(max_bid) = res {
3939
info!(event ="get_header", %req_id, block_hash =% max_bid.data.message.header.block_hash, "header available for slot");
40+
BEACON_NODE_STATUS.with_label_values(&["200", GET_HEADER_ENDPOINT_TAG]).inc();
4041
Ok((StatusCode::OK, axum::Json(max_bid)).into_response())
4142
} else {
4243
// spec: return 204 if request is valid but no bid available
4344
info!(event = "get_header", %req_id, "no header available for slot");
45+
BEACON_NODE_STATUS.with_label_values(&["204", GET_HEADER_ENDPOINT_TAG]).inc();
4446
Ok(StatusCode::NO_CONTENT.into_response())
4547
}
4648
}
4749
Err(err) => {
4850
error!(event = "get_header", %req_id, ?err, "failed relay get_header");
49-
Err(PbsClientError::NoPayload)
51+
let err = PbsClientError::NoPayload;
52+
BEACON_NODE_STATUS
53+
.with_label_values(&[err.status_code().as_str(), GET_HEADER_ENDPOINT_TAG])
54+
.inc();
55+
Err(err)
5056
}
5157
}
5258
}

crates/pbs/src/routes/register_validator.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ use uuid::Uuid;
77

88
use crate::{
99
boost::BuilderApi,
10+
constants::REGISTER_VALIDATOR_ENDPOINT_TAG,
1011
error::PbsClientError,
11-
metrics::REQUESTS_RECEIVED,
12+
metrics::BEACON_NODE_STATUS,
1213
state::{BuilderApiState, PbsState},
1314
BuilderEvent,
1415
};
@@ -18,7 +19,6 @@ pub async fn handle_register_validator<S: BuilderApiState, T: BuilderApi<S>>(
1819
req_headers: HeaderMap,
1920
Json(registrations): Json<Vec<ValidatorRegistration>>,
2021
) -> Result<impl IntoResponse, PbsClientError> {
21-
REQUESTS_RECEIVED.with_label_values(&["register_validator"]).inc();
2222
state.publish_event(BuilderEvent::RegisterValidatorRequest(registrations.clone()));
2323

2424
let req_id = Uuid::new_v4();
@@ -30,9 +30,14 @@ pub async fn handle_register_validator<S: BuilderApiState, T: BuilderApi<S>>(
3030
state.publish_event(BuilderEvent::RegisterValidatorResponse);
3131

3232
error!(method = "register_validator", %req_id, ?err, "all relays failed register_validator");
33-
Err(PbsClientError::NoResponse)
33+
let err = PbsClientError::NoResponse;
34+
BEACON_NODE_STATUS
35+
.with_label_values(&[err.status_code().as_str(), REGISTER_VALIDATOR_ENDPOINT_TAG])
36+
.inc();
37+
Err(err)
3438
} else {
3539
info!(event = "register_validator", %req_id, "register validator successful");
40+
BEACON_NODE_STATUS.with_label_values(&["200", REGISTER_VALIDATOR_ENDPOINT_TAG]).inc();
3641
Ok(StatusCode::OK)
3742
}
3843
}

0 commit comments

Comments
 (0)