use crate::metrics::try_create_int_counter_vec;
use once_cell::sync::Lazy;
use prometheus::{IntCounter, IntCounterVec};
use tracing_subscriber::layer::{Context, Layered};
use tracing_subscriber::registry::LookupSpan;
use tracing_subscriber::Layer;
pub(crate) static LOG_COUNTER: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"unc_log_msg_total",
"Number of messages logged at various log levels",
&["level"],
)
.unwrap()
});
pub(crate) static LOG_WITH_LOCATION_COUNTER: Lazy<IntCounterVec> = Lazy::new(|| {
try_create_int_counter_vec(
"unc_log_msg_with_loc_total",
"Number of messages logged at various log levels wth target and location",
&["level", "target", "file", "line"],
)
.unwrap()
});
pub(crate) type LogCountingLayer<Inner> = Layered<LogCounter, Inner>;
pub(crate) struct LogCounter {
error_metric: IntCounter,
warn_metric: IntCounter,
info_metric: IntCounter,
debug_metric: IntCounter,
trace_metric: IntCounter,
}
impl LogCounter {
fn count_log(&self, level: &tracing::Level) {
match level {
&tracing::Level::ERROR => self.error_metric.inc(),
&tracing::Level::WARN => self.warn_metric.inc(),
&tracing::Level::INFO => self.info_metric.inc(),
&tracing::Level::DEBUG => self.debug_metric.inc(),
&tracing::Level::TRACE => self.trace_metric.inc(),
};
}
fn count_log_with_loc(
&self,
level: &tracing::Level,
target: &str,
file: Option<&str>,
line: Option<u32>,
) {
match level {
&tracing::Level::ERROR | &tracing::Level::WARN | &tracing::Level::INFO => {
LOG_WITH_LOCATION_COUNTER
.with_label_values(&[
&level.as_str(),
target,
file.unwrap_or(""),
&line.map_or("".to_string(), |x| x.to_string()),
])
.inc()
}
_ => {}
};
}
}
impl Default for LogCounter {
fn default() -> Self {
Self {
error_metric: LOG_COUNTER.with_label_values(&["error"]),
warn_metric: LOG_COUNTER.with_label_values(&["warn"]),
info_metric: LOG_COUNTER.with_label_values(&["info"]),
debug_metric: LOG_COUNTER.with_label_values(&["debug"]),
trace_metric: LOG_COUNTER.with_label_values(&["trace"]),
}
}
}
impl<S> Layer<S> for LogCounter
where
S: tracing::Subscriber + for<'span> LookupSpan<'span> + Send + Sync,
{
fn on_event(&self, event: &tracing::Event, _ctx: Context<S>) {
let level = event.metadata().level();
self.count_log(level);
let target = event.metadata().target();
let file = event.metadata().file();
let line = event.metadata().line();
self.count_log_with_loc(level, target, file, line);
}
}