1#![deny(clippy::pedantic)]
2#![allow(clippy::missing_errors_doc)]
3
4use std::net::SocketAddr;
5use std::sync::LazyLock;
6
7use axum::Router;
8use axum::http::StatusCode;
9use axum::routing::get;
10use fedimint_core::task::{TaskGroup, TaskShutdownToken};
11use prometheus::Registry;
12pub use prometheus::{
13 self, Encoder, Gauge, GaugeVec, Histogram, HistogramVec, IntCounter, IntCounterVec,
14 TextEncoder, histogram_opts, opts, register_histogram_with_registry,
15 register_int_counter_vec_with_registry,
16};
17use tokio::net::TcpListener;
18use tracing::error;
19
20pub static REGISTRY: LazyLock<Registry> =
21 LazyLock::new(|| Registry::new_custom(Some("fm".into()), None).unwrap());
22
23pub static AMOUNTS_BUCKETS_SATS: LazyLock<Vec<f64>> = LazyLock::new(|| {
24 vec![
25 0.0,
26 0.1,
27 1.0,
28 10.0,
29 100.0,
30 1000.0,
31 10000.0,
32 100_000.0,
33 1_000_000.0,
34 10_000_000.0,
35 100_000_000.0,
36 ]
37});
38
39async fn get_metrics() -> (StatusCode, String) {
40 let metric_families = REGISTRY.gather();
41 let result = || -> anyhow::Result<String> {
42 let mut buffer = Vec::new();
43 let encoder = TextEncoder::new();
44 encoder.encode(&metric_families, &mut buffer)?;
45 Ok(String::from_utf8(buffer)?)
46 };
47 match result() {
48 Ok(result) => (StatusCode::OK, result),
49 Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, format!("{e:?}")),
50 }
51}
52
53pub async fn run_api_server(
54 bind_address: SocketAddr,
55 task_group: TaskGroup,
56) -> anyhow::Result<TaskShutdownToken> {
57 let app = Router::new().route("/metrics", get(get_metrics));
58 let listener = TcpListener::bind(bind_address).await?;
59 let serve = axum::serve(listener, app.into_make_service());
60
61 let handle = task_group.make_handle();
62 let shutdown_rx = handle.make_shutdown_rx();
63 task_group.spawn("Metrics Api", |_| async {
64 let graceful = serve.with_graceful_shutdown(async {
65 shutdown_rx.await;
66 });
67
68 if let Err(e) = graceful.await {
69 error!("Error shutting down metrics api: {e:?}");
70 }
71 });
72 let shutdown_receiver = handle.make_shutdown_rx();
73
74 Ok(shutdown_receiver)
75}