1pub use float_json_value::FloatJsonValueMetric;
18pub use global::GlobalMetrics;
19pub use prometheus_endpoint::{
20 prometheus::core::{Atomic, Collector},
21 register, Counter, CounterVec, Gauge, GaugeVec, Opts, PrometheusError, Registry, F64, I64, U64,
22};
23
24use async_std::sync::{Arc, RwLock};
25use async_trait::async_trait;
26use std::{fmt::Debug, time::Duration};
27
28mod float_json_value;
29mod global;
30
31pub type F64SharedRef = Arc<RwLock<Option<f64>>>;
33pub type IntGauge = Gauge<U64>;
35
36#[derive(Debug, Clone)]
38pub struct MetricsAddress {
39 pub host: String,
41 pub port: u16,
43}
44
45#[derive(Debug, Clone)]
47pub struct MetricsParams {
48 pub address: Option<MetricsAddress>,
50 pub registry: Registry,
52}
53
54pub trait Metric: Clone + Send + Sync + 'static {
56 fn register(&self, registry: &Registry) -> Result<(), PrometheusError>;
57}
58
59#[async_trait]
64pub trait StandaloneMetric: Metric {
65 async fn update(&self);
67
68 fn update_interval(&self) -> Duration;
70
71 fn register_and_spawn(self, registry: &Registry) -> Result<(), PrometheusError> {
73 match self.register(registry) {
74 Ok(()) => {
75 self.spawn();
76 Ok(())
77 },
78 Err(PrometheusError::AlreadyReg) => Ok(()),
79 Err(e) => Err(e),
80 }
81 }
82
83 fn spawn(self) {
85 async_std::task::spawn(async move {
86 let update_interval = self.update_interval();
87 loop {
88 self.update().await;
89 async_std::task::sleep(update_interval).await;
90 }
91 });
92 }
93}
94
95impl Default for MetricsAddress {
96 fn default() -> Self {
97 MetricsAddress { host: "127.0.0.1".into(), port: 9616 }
98 }
99}
100
101impl MetricsParams {
102 pub fn new(
104 address: Option<MetricsAddress>,
105 relay_version: String,
106 relay_commit: String,
107 ) -> Result<Self, PrometheusError> {
108 const BUILD_INFO_METRIC: &str = "substrate_relay_build_info";
109
110 let registry = Registry::new();
111 register(
112 Gauge::<U64>::with_opts(
113 Opts::new(
114 BUILD_INFO_METRIC,
115 "A metric with a constant '1' value labeled by version",
116 )
117 .const_label("version", &relay_version)
118 .const_label("commit", &relay_commit),
119 )?,
120 ®istry,
121 )?
122 .set(1);
123
124 log::info!(
125 target: "bridge",
126 "Exposed {} metric: version={} commit={}",
127 BUILD_INFO_METRIC,
128 relay_version,
129 relay_commit,
130 );
131
132 Ok(MetricsParams { address, registry })
133 }
134
135 pub fn disabled() -> Self {
137 MetricsParams { address: None, registry: Registry::new() }
138 }
139
140 #[must_use]
142 pub fn disable(mut self) -> Self {
143 self.address = None;
144 self
145 }
146}
147
148pub fn metric_name(prefix: Option<&str>, name: &str) -> String {
150 if let Some(prefix) = prefix {
151 format!("{prefix}_{name}")
152 } else {
153 name.into()
154 }
155}
156
157pub fn set_gauge_value<T: Default + Debug, V: Atomic<T = T>, E: Debug>(
161 gauge: &Gauge<V>,
162 value: Result<Option<T>, E>,
163) {
164 gauge.set(match value {
165 Ok(Some(value)) => {
166 log::trace!(
167 target: "bridge-metrics",
168 "Updated value of metric '{:?}': {:?}",
169 gauge.desc().first().map(|d| &d.fq_name),
170 value,
171 );
172 value
173 },
174 Ok(None) => {
175 log::warn!(
176 target: "bridge-metrics",
177 "Failed to update metric '{:?}': value is empty",
178 gauge.desc().first().map(|d| &d.fq_name),
179 );
180 Default::default()
181 },
182 Err(error) => {
183 log::warn!(
184 target: "bridge-metrics",
185 "Failed to update metric '{:?}': {:?}",
186 gauge.desc().first().map(|d| &d.fq_name),
187 error,
188 );
189 Default::default()
190 },
191 })
192}