1use crate::{
6 report::{report_async, FileReporter, Reportable},
7 report_influxdb::{InfluxdbReportable, InfluxdbReporter},
8 report_prometheus::{PrometheusReportable, PrometheusReporter},
9};
10use cfx_tasks::TaskExecutor;
11use duration_str::deserialize_duration;
12use log::{error, info};
13use serde::{Deserialize, Serialize};
14use std::{
15 sync::atomic::{AtomicBool, Ordering},
16 time::Duration,
17};
18
19pub static ORDER: Ordering = Ordering::Relaxed;
20
21static ENABLED: AtomicBool = AtomicBool::new(false);
22
23pub fn is_enabled() -> bool { ENABLED.load(ORDER) }
24
25pub fn enable() { ENABLED.store(true, ORDER); }
26
27pub trait Metric:
28 Send + Sync + Reportable + InfluxdbReportable + PrometheusReportable
29{
30 fn get_type(&self) -> &str;
31}
32
33#[derive(Debug, Serialize, Deserialize, Clone)]
34#[serde(default)]
35pub struct MetricsConfiguration {
36 pub enabled: bool,
37
38 #[serde(deserialize_with = "deserialize_duration")]
39 pub report_interval: Duration,
40
41 pub file_report_output: Option<String>,
42
43 pub influxdb_report_host: Option<String>,
44 pub influxdb_report_db: String,
45 pub influxdb_report_username: Option<String>,
46 pub influxdb_report_password: Option<String>,
47 pub influxdb_report_node: Option<String>,
48 pub prometheus_listen_addr: Option<String>,
49}
50
51impl Default for MetricsConfiguration {
52 fn default() -> Self {
53 Self {
54 enabled: false,
55 report_interval: Duration::from_secs(10),
56 file_report_output: None,
57 influxdb_report_host: None,
58 influxdb_report_db: "".into(),
59 influxdb_report_username: None,
60 influxdb_report_password: None,
61 influxdb_report_node: None,
62 prometheus_listen_addr: None,
63 }
64 }
65}
66
67pub fn initialize(config: MetricsConfiguration, executor: TaskExecutor) {
68 info!("Initializing metrics with config: {:?}", config);
69 if !config.enabled {
70 return;
71 }
72
73 enable();
74
75 if let Some(output) = config.file_report_output {
77 let reporter = FileReporter::new(output);
78 report_async(reporter, config.report_interval);
79 }
80
81 if let Some(host) = config.influxdb_report_host {
83 let mut auth = None;
84
85 if let Some(username) = config.influxdb_report_username {
86 if let Some(password) = config.influxdb_report_password {
87 auth = Some((username, password));
88 }
89 }
90
91 let mut reporter = match auth {
92 Some((username, password)) => InfluxdbReporter::with_auth(
93 host,
94 config.influxdb_report_db,
95 username,
96 password,
97 ),
98 None => InfluxdbReporter::new(host, config.influxdb_report_db),
99 };
100
101 if let Some(node) = config.influxdb_report_node {
102 reporter.add_tag("node".into(), node);
103 }
104
105 report_async(reporter, config.report_interval);
106 }
107
108 if let Some(addr) = config.prometheus_listen_addr {
111 match PrometheusReporter::new(&addr, executor) {
112 Ok(reporter) => {
113 info!("Initializing PrometheusReporter to listen on {}", addr);
114 match reporter.start_http_server() {
115 Ok(_) => {
116 info!("PrometheusReporter started successfully");
117 }
118 Err(e) => {
119 error!("Failed to start PrometheusReporter: {}", e);
120 }
121 }
122 }
123 Err(e) => {
124 error!("Failed to initialize PrometheusReporter: {}", e);
125 }
126 }
127 }
128}