1use commonware_runtime::{Metrics as _, Spawner as _, tokio::Context};
8use eyre::WrapErr as _;
9use jiff::SignedDuration;
10use reth_node_metrics::recorder::install_prometheus_recorder;
11use reth_tracing::tracing;
12use url::Url;
13
14pub struct PrometheusMetricsConfig {
16 pub endpoint: Url,
18 pub interval: SignedDuration,
20 pub auth_header: Option<String>,
22 pub consensus_pubkey: Option<String>,
24 pub peer_id: String,
26}
27
28pub fn install_prometheus_metrics(
35 context: Context,
36 config: PrometheusMetricsConfig,
37) -> eyre::Result<()> {
38 let interval: std::time::Duration = config
39 .interval
40 .try_into()
41 .wrap_err("invalid metrics duration")?;
42
43 let mut extra_label = format!("peer_id={}", config.peer_id);
44 if let Some(pubkey) = config.consensus_pubkey {
45 extra_label.push_str(&format!(",consensus_pubkey={pubkey}"));
46 }
47
48 let mut endpoint = config.endpoint;
49 endpoint
50 .query_pairs_mut()
51 .append_pair("extra_label", &extra_label);
52
53 let url = endpoint.to_string();
54 let client = reqwest::Client::new();
55 let auth_header = config.auth_header;
56
57 let reth_recorder = install_prometheus_recorder();
58 context.spawn(move |context| async move {
59 use commonware_runtime::Clock as _;
60
61 tracing::info_span!("metrics_exporter", %url).in_scope(|| tracing::info!("started"));
62
63 loop {
64 context.sleep(interval).await;
65
66 let consensus_metrics = context.encode();
67 let reth_metrics = reth_recorder.handle().render();
68 let body = format!("{consensus_metrics}\n{reth_metrics}");
69
70 let mut request = client
72 .post(&url)
73 .header("Content-Type", "text/plain")
74 .body(body);
75
76 if let Some(ref auth) = auth_header {
77 request = request.header("Authorization", auth);
78 }
79
80 let res = request.send().await;
81 tracing::info_span!("metrics_exporter", %url).in_scope(|| match res {
82 Ok(response) if !response.status().is_success() => {
83 tracing::warn!(status = %response.status(), "metrics endpoint returned failure")
84 }
85 Err(reason) => tracing::warn!(%reason, "metrics export failed"),
86 _ => {}
87 });
88 }
89 });
90
91 Ok(())
92}