diff --git a/ringlog/Cargo.toml b/ringlog/Cargo.toml index 63c1fd6..ebc8076 100644 --- a/ringlog/Cargo.toml +++ b/ringlog/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ringlog" -version = "0.7.0" +version = "0.8.0" edition = "2021" license = "Apache-2.0" authors = ["Brian Martin "] @@ -11,6 +11,9 @@ repository = "https://github.com/pelikan-io/rustcommon" [dependencies] ahash = "0.8.0" clocksource = { version = "0.8.0", path = "../clocksource" } -metriken = "0.7.0" log = { version = "0.4.17", features = ["std"] } +metriken = { version = "0.7.0", optional = true } mpmc = "0.1.6" + +[features] +metrics = ["metriken"] diff --git a/ringlog/src/lib.rs b/ringlog/src/lib.rs index 7533910..60f08ab 100644 --- a/ringlog/src/lib.rs +++ b/ringlog/src/lib.rs @@ -37,6 +37,8 @@ pub use log::*; mod format; +#[macro_use] +mod macros; mod multi; mod nop; mod outputs; @@ -52,88 +54,17 @@ pub use sampling::*; pub use single::*; pub use traits::*; +#[cfg(feature = "metrics")] +mod metrics; + +#[cfg(feature = "metrics")] +use metrics::*; + use clocksource::datetime::DateTime; use mpmc::Queue; pub(crate) type LogBuffer = Vec; -use metriken::{metric, Counter, Gauge}; - -#[metric(name = "log_create", description = "logging targets initialized")] -pub static LOG_CREATE: Counter = Counter::new(); - -#[metric( - name = "log_create_ex", - description = "number of exceptions while initializing logging targets" -)] -pub static LOG_CREATE_EX: Counter = Counter::new(); - -#[metric(name = "log_destroy", description = "logging targets destroyed")] -pub static LOG_DESTROY: Counter = Counter::new(); - -#[metric(name = "log_curr", description = "current number of logging targets")] -pub static LOG_CURR: Gauge = Gauge::new(); - -#[metric( - name = "log_open", - description = "number of logging destinations which have been opened" -)] -pub static LOG_OPEN: Counter = Counter::new(); - -#[metric( - name = "log_open_ex", - description = "number of exceptions while opening logging destinations" -)] -pub static LOG_OPEN_EX: Counter = Counter::new(); - -#[metric( - name = "log_write", - description = "number of writes to all logging destinations" -)] -pub static LOG_WRITE: Counter = Counter::new(); - -#[metric( - name = "log_write_byte", - description = "number of bytes written to all logging destinations" -)] -pub static LOG_WRITE_BYTE: Counter = Counter::new(); - -#[metric( - name = "log_write_ex", - description = "number of exceptions while writing to logging destinations" -)] -pub static LOG_WRITE_EX: Counter = Counter::new(); - -#[metric( - name = "log_skip", - description = "number of log messages skipped due to sampling policy" -)] -pub static LOG_SKIP: Counter = Counter::new(); - -#[metric( - name = "log_drop", - description = "number of log messages dropped due to full queues" -)] -pub static LOG_DROP: Counter = Counter::new(); - -#[metric( - name = "log_drop_byte", - description = "number of bytes dropped due to full queues" -)] -pub static LOG_DROP_BYTE: Counter = Counter::new(); - -#[metric( - name = "log_flush", - description = "number of times logging destinations have been flushed" -)] -pub static LOG_FLUSH: Counter = Counter::new(); - -#[metric( - name = "log_flush_ex", - description = "number of times logging destinations have been flushed" -)] -pub static LOG_FLUSH_EX: Counter = Counter::new(); - /// A type which implements an asynchronous logging backend. pub struct RingLog { pub(crate) logger: Box, @@ -152,19 +83,3 @@ impl RingLog { self.drain } } - -#[macro_export] -macro_rules! fatal { - () => ( - error!(); - std::process::exit(1); - ); - ($fmt:expr) => ( - error!($fmt); - std::process::exit(1); - ); - ($fmt:expr, $($arg:tt)*) => ( - error!($fmt, $($arg)*); - std::process::exit(1); - ); -} diff --git a/ringlog/src/macros.rs b/ringlog/src/macros.rs new file mode 100644 index 0000000..2ae141f --- /dev/null +++ b/ringlog/src/macros.rs @@ -0,0 +1,26 @@ +#[macro_export] +/// Logs a fatal error and terminates the program. +macro_rules! fatal { + () => ( + error!(); + std::process::exit(1); + ); + ($fmt:expr) => ( + error!($fmt); + std::process::exit(1); + ); + ($fmt:expr, $($arg:tt)*) => ( + error!($fmt, $($arg)*); + std::process::exit(1); + ); +} + +#[cfg(feature = "metrics")] +macro_rules! metrics { + { $( $tt:tt )* } => { $( $tt )* } +} + +#[cfg(not(feature = "metrics"))] +macro_rules! metrics { + { $( $tt:tt)* } => {} +} diff --git a/ringlog/src/metrics.rs b/ringlog/src/metrics.rs new file mode 100644 index 0000000..cda7383 --- /dev/null +++ b/ringlog/src/metrics.rs @@ -0,0 +1,76 @@ +use metriken::{metric, Counter, Gauge}; + +#[metric(name = "log_create", description = "logging targets initialized")] +pub static LOG_CREATE: Counter = Counter::new(); + +#[metric( + name = "log_create_ex", + description = "number of exceptions while initializing logging targets" +)] +pub static LOG_CREATE_EX: Counter = Counter::new(); + +#[metric(name = "log_destroy", description = "logging targets destroyed")] +pub static LOG_DESTROY: Counter = Counter::new(); + +#[metric(name = "log_curr", description = "current number of logging targets")] +pub static LOG_CURR: Gauge = Gauge::new(); + +#[metric( + name = "log_open", + description = "number of logging destinations which have been opened" +)] +pub static LOG_OPEN: Counter = Counter::new(); + +#[metric( + name = "log_open_ex", + description = "number of exceptions while opening logging destinations" +)] +pub static LOG_OPEN_EX: Counter = Counter::new(); + +#[metric( + name = "log_write", + description = "number of writes to all logging destinations" +)] +pub static LOG_WRITE: Counter = Counter::new(); + +#[metric( + name = "log_write_byte", + description = "number of bytes written to all logging destinations" +)] +pub static LOG_WRITE_BYTE: Counter = Counter::new(); + +#[metric( + name = "log_write_ex", + description = "number of exceptions while writing to logging destinations" +)] +pub static LOG_WRITE_EX: Counter = Counter::new(); + +#[metric( + name = "log_skip", + description = "number of log messages skipped due to sampling policy" +)] +pub static LOG_SKIP: Counter = Counter::new(); + +#[metric( + name = "log_drop", + description = "number of log messages dropped due to full queues" +)] +pub static LOG_DROP: Counter = Counter::new(); + +#[metric( + name = "log_drop_byte", + description = "number of bytes dropped due to full queues" +)] +pub static LOG_DROP_BYTE: Counter = Counter::new(); + +#[metric( + name = "log_flush", + description = "number of times logging destinations have been flushed" +)] +pub static LOG_FLUSH: Counter = Counter::new(); + +#[metric( + name = "log_flush_ex", + description = "number of times logging destinations have been flushed" +)] +pub static LOG_FLUSH_EX: Counter = Counter::new(); diff --git a/ringlog/src/outputs.rs b/ringlog/src/outputs.rs index 929da11..4745edd 100644 --- a/ringlog/src/outputs.rs +++ b/ringlog/src/outputs.rs @@ -81,11 +81,17 @@ impl File { /// file. When the size of the live log is exceeded, it will automatically /// be rotated to the backup path. pub fn new>(active: T, backup: T, max_size: u64) -> Result { - LOG_OPEN.increment(); + metrics! { + LOG_OPEN.increment(); + } + let file = match std::fs::File::create(active.as_ref()) { Ok(f) => f, Err(e) => { - LOG_OPEN_EX.increment(); + metrics! { + LOG_OPEN_EX.increment(); + } + return Err(e); } }; @@ -111,11 +117,18 @@ impl File { std::fs::rename(&self.active, &self.backup)?; // create a new file for the live log - LOG_OPEN.increment(); + + metrics! { + LOG_OPEN.increment(); + } + let file = match std::fs::File::create(&self.active) { Ok(f) => f, Err(e) => { - LOG_OPEN_EX.increment(); + metrics! { + LOG_OPEN_EX.increment(); + } + return Err(e); } }; diff --git a/ringlog/src/sampling.rs b/ringlog/src/sampling.rs index ec8f18e..9e35948 100644 --- a/ringlog/src/sampling.rs +++ b/ringlog/src/sampling.rs @@ -32,10 +32,13 @@ impl Log for SamplingLogger { let count = self.counter.fetch_add(1, Ordering::Relaxed); // if this is the Nth message, we should log it + #[allow(clippy::needless_else)] if (count % self.sample) == 0 { self.logger.log(record) } else { - LOG_SKIP.increment(); + metrics! { + LOG_SKIP.increment(); + } } } diff --git a/ringlog/src/single.rs b/ringlog/src/single.rs index 6e39b6d..316aa4d 100644 --- a/ringlog/src/single.rs +++ b/ringlog/src/single.rs @@ -47,7 +47,9 @@ impl Log for Logger { ) .is_ok() { - let bytes = buffer.len(); + metrics! { + let bytes = buffer.len(); + } // Note this may drop a log message, but avoids blocking. The // preference here is to preserve log messages which lead up to the @@ -55,12 +57,17 @@ impl Log for Logger { // error begins to happen which causes very many log messages, it is // more beneficial to have the history leading up to the issue than // to preserve more recent error messages. + #[allow(clippy::needless_else)] if self.log_filled.push(buffer).is_ok() { - LOG_WRITE.increment(); - LOG_WRITE_BYTE.add(bytes as _); + metrics! { + LOG_WRITE.increment(); + LOG_WRITE_BYTE.add(bytes as _); + } } else { - LOG_DROP.increment(); - LOG_DROP_BYTE.add(bytes as _); + metrics! { + LOG_DROP.increment(); + LOG_DROP_BYTE.add(bytes as _); + } } } } @@ -79,10 +86,16 @@ pub(crate) struct LogDrain { impl Drain for LogDrain { fn flush(&mut self) -> Result<(), Error> { - LOG_FLUSH.increment(); + metrics! { + LOG_FLUSH.increment(); + } + while let Some(mut log_buffer) = self.log_filled.pop() { if let Err(e) = self.output.write_all(&log_buffer) { - LOG_WRITE_EX.increment(); + metrics! { + LOG_WRITE_EX.increment(); + } + warn!("failed write to log buffer: {}", e); return Err(e); } @@ -100,7 +113,10 @@ impl Drain for LogDrain { } if let Err(e) = self.output.flush() { - LOG_FLUSH_EX.increment(); + metrics! { + LOG_FLUSH_EX.increment(); + } + warn!("failed to flush log: {}", e); Err(e) } else { @@ -166,8 +182,11 @@ impl LogBuilder { /// Consumes the builder and returns a configured `Logger` and `LogHandle`. pub(crate) fn build_raw(self) -> Result<(Logger, LogDrain), &'static str> { - LOG_CREATE.increment(); - LOG_CURR.increment(); + metrics! { + LOG_CREATE.increment(); + LOG_CURR.increment(); + } + if let Some(output) = self.output { let log_filled = Queue::with_capacity(self.log_queue_depth); let log_cleared = Queue::with_capacity(self.log_queue_depth); @@ -189,7 +208,10 @@ impl LogBuilder { }; Ok((logger, log_handle)) } else { - LOG_CREATE_EX.increment(); + metrics! { + LOG_CREATE_EX.increment(); + } + Err("no output configured") } } @@ -208,7 +230,9 @@ impl LogBuilder { impl Drop for Logger { fn drop(&mut self) { - LOG_DESTROY.increment(); - LOG_CURR.decrement(); + metrics! { + LOG_DESTROY.increment(); + LOG_CURR.decrement(); + } } }