Skip to content

Commit 46428fa

Browse files
ManuelBilbaoltitanb
authored andcommitted
feat(signer): add metrics (#197)
* Add endpoints metrics * Add grafana dashboard * Add more stats to dashboard * Fix clippy * Fix doc comments * Make signer metrics function private * Export signer dashboard for public use
1 parent 67b9b0e commit 46428fa

File tree

10 files changed

+994
-2
lines changed

10 files changed

+994
-2
lines changed

Cargo.lock

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

crates/signer/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ publish = false
77

88
[dependencies]
99
cb-common.workspace = true
10+
cb-metrics.workspace = true
1011

1112
# ethereum
1213
alloy.workspace = true
@@ -21,6 +22,7 @@ tokio.workspace = true
2122

2223
# telemetry
2324
tracing.workspace = true
25+
prometheus.workspace = true
2426

2527
# crypto
2628
blst.workspace = true

crates/signer/src/constants.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub const GET_PUBKEYS_ENDPOINT_TAG: &str = "get_pubkeys";
2+
pub const GENERATE_PROXY_KEY_ENDPOINT_TAG: &str = "generate_proxy_key";
3+
pub const REQUEST_SIGNATURE_ENDPOINT_TAG: &str = "request_signature";

crates/signer/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
mod constants;
12
pub mod error;
23
pub mod manager;
4+
mod metrics;
35
pub mod service;

crates/signer/src/metrics.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//! Metrics for Signer module
2+
3+
use axum::http::Uri;
4+
use cb_common::commit::constants::{
5+
GENERATE_PROXY_KEY_PATH, GET_PUBKEYS_PATH, REQUEST_SIGNATURE_PATH,
6+
};
7+
use lazy_static::lazy_static;
8+
use prometheus::{register_int_counter_vec_with_registry, IntCounterVec, Registry};
9+
10+
use crate::constants::{
11+
GENERATE_PROXY_KEY_ENDPOINT_TAG, GET_PUBKEYS_ENDPOINT_TAG, REQUEST_SIGNATURE_ENDPOINT_TAG,
12+
};
13+
14+
lazy_static! {
15+
pub static ref SIGNER_METRICS_REGISTRY: Registry =
16+
Registry::new_custom(Some("cb_signer".to_string()), None).unwrap();
17+
18+
/// Status code returned by endpoint
19+
pub static ref SIGNER_STATUS: IntCounterVec = register_int_counter_vec_with_registry!(
20+
"signer_status_code_total",
21+
"HTTP status code returned by signer",
22+
&["http_status_code", "endpoint"],
23+
SIGNER_METRICS_REGISTRY
24+
).unwrap();
25+
}
26+
27+
pub fn uri_to_tag(uri: &Uri) -> &str {
28+
match uri.path() {
29+
GET_PUBKEYS_PATH => GET_PUBKEYS_ENDPOINT_TAG,
30+
GENERATE_PROXY_KEY_PATH => GENERATE_PROXY_KEY_ENDPOINT_TAG,
31+
REQUEST_SIGNATURE_PATH => REQUEST_SIGNATURE_ENDPOINT_TAG,
32+
_ => "unknown endpoint",
33+
}
34+
}

crates/signer/src/service.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,18 @@ use cb_common::{
2424
constants::COMMIT_BOOST_VERSION,
2525
types::{Jwt, ModuleId},
2626
};
27+
use cb_metrics::provider::MetricsProvider;
2728
use eyre::{Context, Result};
2829
use headers::{authorization::Bearer, Authorization};
2930
use tokio::{net::TcpListener, sync::RwLock};
3031
use tracing::{debug, error, info, warn};
3132
use uuid::Uuid;
3233

33-
use crate::{error::SignerModuleError, manager::SigningManager};
34+
use crate::{
35+
error::SignerModuleError,
36+
manager::SigningManager,
37+
metrics::{uri_to_tag, SIGNER_METRICS_REGISTRY, SIGNER_STATUS},
38+
};
3439

3540
/// Implements the Signer API and provides a service for signing requests
3641
pub struct SigningService;
@@ -72,13 +77,15 @@ impl SigningService {
7277
info!(version = COMMIT_BOOST_VERSION, modules =? module_ids, port =? config.server_port, loaded_consensus, loaded_proxies, "Starting signing service");
7378

7479
let state = SigningState { manager: RwLock::new(manager).into(), jwts: config.jwts.into() };
80+
SigningService::init_metrics()?;
7581

7682
let app = axum::Router::new()
7783
.route(REQUEST_SIGNATURE_PATH, post(handle_request_signature))
7884
.route(GET_PUBKEYS_PATH, get(handle_get_pubkeys))
7985
.route(GENERATE_PROXY_KEY_PATH, post(handle_generate_proxy))
8086
.with_state(state.clone())
81-
.route_layer(middleware::from_fn_with_state(state.clone(), jwt_auth));
87+
.route_layer(middleware::from_fn_with_state(state.clone(), jwt_auth))
88+
.route_layer(middleware::from_fn(log_request));
8289
let status_router = axum::Router::new().route(STATUS_PATH, get(handle_status));
8390

8491
let address = SocketAddr::from(([0, 0, 0, 0], config.server_port));
@@ -88,6 +95,10 @@ impl SigningService {
8895
.await
8996
.wrap_err("signer server exited")
9097
}
98+
99+
fn init_metrics() -> Result<()> {
100+
MetricsProvider::load_and_run(SIGNER_METRICS_REGISTRY.clone())
101+
}
91102
}
92103

93104
/// Authentication middleware layer
@@ -109,6 +120,14 @@ async fn jwt_auth(
109120
Ok(next.run(req).await)
110121
}
111122

123+
/// Requests logging middleware layer
124+
async fn log_request(req: Request, next: Next) -> Result<Response, SignerModuleError> {
125+
let url = &req.uri().clone();
126+
let response = next.run(req).await;
127+
SIGNER_STATUS.with_label_values(&[response.status().as_str(), uri_to_tag(url)]).inc();
128+
Ok(response)
129+
}
130+
112131
/// Status endpoint for the Signer API
113132
async fn handle_status() -> Result<impl IntoResponse, SignerModuleError> {
114133
Ok((StatusCode::OK, "OK"))
File renamed without changes.

0 commit comments

Comments
 (0)