use super::prelude::LOG_TARGET; use futures::channel::oneshot; pub use hidden::*; use hyper::{ header::CONTENT_TYPE, service::{make_service_fn, service_fn}, Body, Method, Request, Response, }; use prometheus::{Encoder, TextEncoder}; async fn serve_req(req: Request) -> Result, hyper::Error> { let response = match (req.method(), req.uri().path()) { (&Method::GET, "/metrics") => { let mut buffer = vec![]; let encoder = TextEncoder::new(); let metric_families = prometheus::gather(); encoder.encode(&metric_families, &mut buffer).unwrap(); Response::builder() .status(200) .header(CONTENT_TYPE, encoder.format_type()) .body(Body::from(buffer)) .unwrap() }, (&Method::GET, "/") => Response::builder().status(200).body(Body::from("")).unwrap(), _ => Response::builder().status(404).body(Body::from("")).unwrap(), }; Ok(response) } pub struct GracefulShutdown(Option>); impl Drop for GracefulShutdown { fn drop(&self) { if let Some(handle) = self.0.take() { let _ = handle.send(()); } } } pub fn run(port: u16) -> Result { let (tx, rx) = oneshot::channel(); let make_svc = make_service_fn(move |_conn| async move { Ok::<_, std::convert::Infallible>(service_fn(serve_req)) }); let addr = ([0, 0, 0, 0], port).into(); let server = hyper::Server::try_bind(&addr) .map_err(|e| format!("Failed bind socket on port {} {:?}", port, e))? .serve(make_svc); log::info!(target: LOG_TARGET, "Started prometheus endpoint on http://{}", addr); let graceful = server.with_graceful_shutdown(async { rx.await.ok(); }); tokio::spawn(async move { if let Err(e) = graceful.await { log::warn!("Server error: {}", e); } }); Ok(GracefulShutdown(Some(tx))) } mod hidden { use frame_election_provider_support::Weight; use once_cell::sync::Lazy; use prometheus::{opts, register_counter, register_gauge, Counter, Gauge}; static TRIMMED_SOLUTION_STARTED: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_trim_started", "Number of started trimmed solutions", )).unwrap() }); static TRIMMED_SOLUTION_SUCCESS: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_trim_success", "Number of successful trimmed solutions", )).unwrap() }); static SUBMISSIONS_STARTED: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_submissions_started", "Number of submissions started", )).unwrap() }); static SUBMISSIONS_SUCCESS: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_submissions_success", "Number of submissions finished successfully", )).unwrap() }); static MINED_SOLUTION_DURATION: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_mining_duration_ms", "The mined solution time in milliseconds.", )).unwrap() }); static SUBMIT_SOLUTION_AND_WATCH_DURATION: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_submit_and_watch_duration_ms", "The time in milliseconds it took to submit the solution to chain and to be included in block.", )).unwrap() }); static BALANCE: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_balance", "The balance of the staking miner account", )).unwrap() }); static SCORE_MINIMAL_STAKE: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_score_minimal_stake", "The minimal winner, in terms of total backing stake", )).unwrap() }); static SCORE_SUM_STAKE: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_score_sum_stake", "The sum of the total backing of all winners", )).unwrap() }); static SCORE_SUM_STAKE_SQUARED: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_score_sum_stake_squared", "The sum of the total backing of all winners, aka. the variance.", )).unwrap() }); static RUNTIME_UPGRADES: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_runtime", "Number of runtime upgrades performed", )).unwrap() }); static SUBMISSION_LENGTH: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_solution_length_bytes", "Number of bytes in the solution submitted", )).unwrap() }); static SUBMISSION_WEIGHT: Lazy = Lazy::new(|| { register_counter!(opts!( "staking_miner_solution_weight", "Weight of the solution submitted", )).unwrap() }); pub fn on_runtime_upgrade() { RUNTIME_UPGRADES.inc(); } pub fn on_submission_attempts() { SUBMISSIONS_STARTED.inc(); } pub fn on_submission_success() { SUBMISSIONS_SUCCESS.inc(); } pub fn on_trim_attempt() { TRIMMED_SOLUTION_STARTED.inc(); } pub fn on_trim_success() { TRIMMED_SOLUTION_SUCCESS.inc(); } pub fn set_balance(balance: u64) { BALANCE.set(balance); } pub fn set_length(len: usize) { SUBMISSION_LENGTH.set(len as f64); } pub fn set_weight(weight: Weight) { SUBMISSION_WEIGHT.set(weight.ref_time() as f64); } pub fn set_score(score: sp_npos_elections::ElectionScore) { SCORE_MINIMAL_STAKE.set(score.minimal_stake as f64); SCORE_SUM_STAKE.set(score.sum_stake as f64); SCORE_SUM_STAKE_SQUARED.set(score.sum_stake_squared as f64); } pub fn observe_submit_and_watch_duration(time: f64) { SUBMIT_SOLUTION_AND_WATCH_DURATION.set(time); } pub fn observe_mined_solution_duration(time: f64) { MINED_SOLUTION_DURATION.set(time); } }