diff --git a/proxmox-log/src/builder.rs b/proxmox-log/src/builder.rs index f7db38a9..5725b4c0 100644 --- a/proxmox-log/src/builder.rs +++ b/proxmox-log/src/builder.rs @@ -4,7 +4,7 @@ use tracing_subscriber::{filter::filter_fn, layer::SubscriberExt, Layer}; use crate::{ get_env_variable, journald_or_stderr_layer, plain_stderr_layer, - tasklog_layer::TasklogLayer, LogContext, + pve_task_formatter::PveTaskFormatter, tasklog_layer::TasklogLayer, LogContext, }; /// Builder-like struct to compose your logging layers. @@ -114,6 +114,20 @@ impl Logger { self } + /// Print to stderr in the PVE format. + /// + /// The PVE format only prints the event level and messages. + /// e.g.: `DEBUG: event message`. + pub fn stderr_pve(mut self) -> Logger { + let layer = tracing_subscriber::fmt::layer() + .event_format(PveTaskFormatter {}) + .with_writer(std::io::stderr) + .with_filter(self.global_log_level) + .boxed(); + self.layer.push(layer); + self + } + /// Inits the tracing logger with the previously configured layers. /// /// Also configures the `LogTracer` which will convert all `log` events to tracing events. diff --git a/proxmox-log/src/lib.rs b/proxmox-log/src/lib.rs index 51ca89ac..2f4d4dab 100644 --- a/proxmox-log/src/lib.rs +++ b/proxmox-log/src/lib.rs @@ -9,6 +9,7 @@ use tokio::task::futures::TaskLocalFuture; use tracing_subscriber::prelude::*; mod file_logger; +mod pve_task_formatter; mod tasklog_layer; pub mod builder; diff --git a/proxmox-log/src/pve_task_formatter.rs b/proxmox-log/src/pve_task_formatter.rs new file mode 100644 index 00000000..e9866a4b --- /dev/null +++ b/proxmox-log/src/pve_task_formatter.rs @@ -0,0 +1,31 @@ +use std::fmt; +use tracing::{Event, Subscriber}; +use tracing_subscriber::field::VisitOutput; +use tracing_subscriber::fmt::format::{DefaultVisitor, Writer}; +use tracing_subscriber::fmt::{FmtContext, FormatEvent, FormatFields}; +use tracing_subscriber::registry::LookupSpan; + +/// This custom formatter outputs logs as they are visible in the PVE task log. +/// +/// e.g.: "DEBUG: sample message" +pub struct PveTaskFormatter {} + +impl FormatEvent for PveTaskFormatter +where + C: Subscriber + for<'a> LookupSpan<'a>, + N: for<'a> FormatFields<'a> + 'static, +{ + fn format_event( + &self, + _ctx: &FmtContext<'_, C, N>, + mut writer: Writer<'_>, + event: &Event<'_>, + ) -> fmt::Result { + write!(writer, "{}: ", event.metadata().level().as_str())?; + + let mut v = DefaultVisitor::new(writer.by_ref(), true); + event.record(&mut v); + v.finish()?; + writer.write_char('\n') + } +}