use metrics_exporter_prometheus::PrometheusBuilder;
use std::net::SocketAddr;
use cirious_codex_logger::{Dispatcher, JsonFormatter, Level, Record, StdoutDispatcher, StyledTerminalFormatter};
use cirious_codex_result::{codex_ok, CodexError, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum LogFormat {
Json,
Styled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TelemetryBuilder {
prometheus_addr: SocketAddr,
log_format: LogFormat,
}
impl Default for TelemetryBuilder {
fn default() -> Self {
Self {
prometheus_addr: SocketAddr::from(([0, 0, 0, 0], 9000)),
log_format: LogFormat::Styled,
}
}
}
impl TelemetryBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub const fn with_format(mut self, format: LogFormat) -> Self {
self.log_format = format;
self
}
#[must_use]
pub const fn with_prometheus_addr(mut self, addr: SocketAddr) -> Self {
self.prometheus_addr = addr;
self
}
pub fn init(self) -> Result<()> {
PrometheusBuilder::new()
.with_http_listener(self.prometheus_addr)
.install()
.map_err(|e|
CodexError::builder("PROMETHEUS_INIT_FAILED", "Failed to install global Prometheus recorder")
.with_suggestion("Verify if the network port is already allocated by another process or if the application lacks binding permissions.")
.with_meta("target_address", self.prometheus_addr.to_string())
.with_meta("underlying_error", e.to_string())
)?;
match self.log_format {
LogFormat::Json => {
let dispatcher = StdoutDispatcher::new(JsonFormatter);
codex_ok!(dispatcher.dispatch(&Record {
level: Level::Info,
args: format_args!(
"Prometheus metrics exporter running at http://{}/metrics",
self.prometheus_addr
),
}))
}
LogFormat::Styled => {
let dispatcher = StdoutDispatcher::new(StyledTerminalFormatter);
codex_ok!(dispatcher.dispatch(&Record {
level: Level::Info,
args: format_args!(
"📊 Prometheus metrics exporter running at http://{}/metrics",
self.prometheus_addr
),
}))
}
}
}
}