From: Gabriel Goller <g.goller@proxmox.com>
To: Wolfgang Bumiller <w.bumiller@proxmox.com>
Cc: Lukas Wagner <l.wagner@proxmox.com>, pbs-devel@lists.proxmox.com
Subject: Re: [pbs-devel] [PATCH proxmox v7 1/4] proxmox-log: add tracing infrastructure
Date: Thu, 4 Jul 2024 11:24:28 +0200 [thread overview]
Message-ID: <20240704092428.2fgqr7sdmwib4p67@luna.proxmox.com> (raw)
In-Reply-To: <incg7q2xxeu3vbaf62nbpwv7udvsaoqt4e46mioye2smcvstud@w4kp2juzew7q>
On 03.07.2024 16:05, Wolfgang Bumiller wrote:
>On Mon, Jul 01, 2024 at 11:26:30AM GMT, Gabriel Goller wrote:
>> diff --git a/proxmox-log/src/file_logger.rs b/proxmox-log/src/file_logger.rs
>> +/// Log messages with optional automatically added timestamps into files
>> +///
>> +/// #### Example:
>> +/// ```
>> +/// # use anyhow::{bail, format_err, Error};
>> +/// use proxmox_log::{flog, FileLogger, FileLogOptions};
>> +///
>> +/// # std::fs::remove_file("test.log");
>> +/// let options = FileLogOptions {
>> +/// to_stdout: true,
>> +/// exclusive: true,
>> +/// ..Default::default()
>> +/// };
>> +/// let mut log = FileLogger::new("test.log", options).unwrap();
>> +/// flog!(log, "A simple log: {}", "Hello!");
>> +/// # std::fs::remove_file("test.log");
>> +/// ```
>> +pub struct FileLogger {
>> + file: std::fs::File,
>> + file_name: std::path::PathBuf,
>> + options: FileLogOptions,
>> +}
>> +
>> +/// Log messages to [FileLogger] - ``println`` like macro
>> +#[macro_export]
>> +macro_rules! flog {
>
>AFAICT this is completely unused and I don't think we'll actually be
>using FileLogger like this anyway, so I'd say we can drop this.
I agree, removed it and adjusted the comment above.
>> + ($log:expr, $($arg:tt)*) => ({
>> + $log.log(format!($($arg)*));
>> + })
>> +}
>> +
>> +impl FileLogger {
>> + /// Create a new FileLogger. This opens the specified file and
>> + /// stores a file descriptor.
>> + pub fn new<P: AsRef<std::path::Path>>(
>> + file_name: P,
>> + options: FileLogOptions,
>> + ) -> Result<Self, Error> {
>> + let file = Self::open(&file_name, &options)?;
>> +
>> + let file_name: std::path::PathBuf = file_name.as_ref().to_path_buf();
>> +
>> + Ok(Self {
>> + file,
>> + file_name,
>> + options,
>> + })
>> + }
>> +
>> + /// Reopen logfile.
>> + pub fn reopen(&mut self) -> Result<&Self, Error> {
>> + let file = Self::open(&self.file_name, &self.options)?;
>> + self.file = file;
>> + Ok(self)
>> + }
>> +
>> + fn open<P: AsRef<std::path::Path>>(
>> + file_name: P,
>> + options: &FileLogOptions,
>> + ) -> Result<std::fs::File, Error> {
>> + let mut flags = OFlag::O_CLOEXEC;
>> +
>> + if options.read {
>> + flags |= OFlag::O_RDWR;
>> + } else {
>> + flags |= OFlag::O_WRONLY;
>> + }
>> +
>> + if options.append {
>> + flags |= OFlag::O_APPEND;
>> + }
>> + if options.exclusive {
>> + flags |= OFlag::O_EXCL;
>> + }
>> +
>> + let file =
>> + atomic_open_or_create_file(&file_name, flags, &[], options.file_opts.clone(), false)?;
>> +
>> + Ok(file)
>> + }
>> +
>> + /// Writes `msg` to the logfile with a timestamp and to stdout if
>> + /// specified.
>> + pub fn log<S: AsRef<str>>(&mut self, msg: S) {
>> + let msg = msg.as_ref();
>> +
>> + if self.options.to_stdout {
>> + let mut stdout = std::io::stdout();
>> + let _ = stdout.write_all(msg.as_bytes());
>> + let _ = stdout.write_all(b"\n");
>> + }
>> +
>> + let line = if self.options.prefix_time {
>> + let now = proxmox_time::epoch_i64();
>> + let rfc3339 = match proxmox_time::epoch_to_rfc3339(now) {
>> + Ok(rfc3339) => rfc3339,
>> + Err(_) => "1970-01-01T00:00:00Z".into(), // for safety, should really not happen!
>> + };
>> + format!("{rfc3339}: {msg}\n")
>> + } else {
>> + format!("{msg}\n")
>> + };
>> + // Note: we ignore the potential error here because log methods
>> + // shouldn't panic. We also can't log an error, because that
>> + // would lead to recursion.
>> + let _ = self.file.write_all(line.as_bytes());
>> + }
>> +}
>> +
>> +impl std::io::Write for FileLogger {
>> + fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
>> + if self.options.to_stdout {
>> + let _ = std::io::stdout().write(buf);
>> + }
>> + self.file.write(buf)
>> + }
>> +
>> + fn flush(&mut self) -> Result<(), std::io::Error> {
>> + if self.options.to_stdout {
>> + let _ = std::io::stdout().flush();
>> + }
>> + self.file.flush()
>> + }
>> +}
>> diff --git a/proxmox-log/src/lib.rs b/proxmox-log/src/lib.rs
>> new file mode 100644
>> index 000000000000..5fd7ac1c4636
>> --- /dev/null
>> +++ b/proxmox-log/src/lib.rs
>> @@ -0,0 +1,52 @@
>> +use std::{
>> + cell::{Cell, RefCell},
>> + env,
>> +};
>> +
>> +use tracing::Level;
>> +use tracing_log::{AsLog, LogTracer};
>> +use tracing_subscriber::filter::{filter_fn, LevelFilter};
>> +use tracing_subscriber::prelude::*;
>> +
>> +use tasklog_layer::TasklogLayer;
>> +
>> +mod file_logger;
>> +pub use file_logger::{FileLogOptions, FileLogger};
>> +
>> +mod tasklog_layer;
>> +
>> +tokio::task_local! {
>> + pub static LOGGER: RefCell<FileLogger>;
>> + pub static WARN_COUNTER: Cell<u64>;
>> +}
>> +
>> +pub fn init_logger(
>> + env_var_name: &str,
>> + default_log_level: LevelFilter,
>> + _application_name: &str,
>> +) -> Result<(), anyhow::Error> {
>> + let mut log_level = default_log_level;
>> + if let Ok(v) = env::var(env_var_name) {
>> + if let Ok(l) = v.parse::<LevelFilter>() {
>> + log_level = l;
>> + }
>> + }
>> + let registry = tracing_subscriber::registry()
>> + .with(
>> + tracing_journald::layer()
>> + .expect("Unable to open syslog")
>> + .with_filter(log_level)
>> + .with_filter(filter_fn(|metadata| {
>> + LOGGER.try_with(|_| {}).is_err() || *metadata.level() == Level::ERROR
>> + })),
>> + )
>> + .with(
>> + TasklogLayer {}
>> + .with_filter(log_level)
>> + .with_filter(filter_fn(|_| LOGGER.try_with(|_| {}).is_ok())),
>> + );
>> +
>> + tracing::subscriber::set_global_default(registry)?;
>> + LogTracer::init_with_filter(log_level.as_log())?;
>> + Ok(())
>> +}
>> diff --git a/proxmox-log/src/tasklog_layer.rs b/proxmox-log/src/tasklog_layer.rs
>> new file mode 100644
>> index 000000000000..e25ded8cbcd4
>> --- /dev/null
>> +++ b/proxmox-log/src/tasklog_layer.rs
>> @@ -0,0 +1,59 @@
>> +use std::fmt::Write as _;
>> +
>> +use tracing::field::Field;
>> +use tracing::field::Visit;
>> +use tracing::Event;
>> +use tracing::Level;
>> +use tracing::Subscriber;
>> +use tracing_subscriber::layer::Context;
>> +use tracing_subscriber::Layer;
>> +
>> +use crate::FileLogger;
>> +use crate::LOGGER;
>> +use crate::WARN_COUNTER;
>> +
>> +pub struct TasklogLayer;
>> +
>> +impl<S: Subscriber> Layer<S> for TasklogLayer {
>> + fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
>> + let mut buf = String::new();
>> + event.record(&mut EventVisitor::new(&mut buf));
>> + let level = event.metadata().level();
>
>I actually mentioned this in a very early version: The string should be
>built within the try_with closure below, since if we don't have a
>LOGGER we'll only be throwing it away.
Oops, yeah this is my bad. It somehow sneaked in again in the last
version :(
>This does also make me wonder if we really need the filter on the layer
>to test whether LOGGER is usable... not sure how efficient the
>implementation is on the tracing crate side if the on_event method is
>entered.
I removed it from the task-log layer and did some quick benchmarking:
Benchmark 1: ./target/debug/slow
Time (mean ± σ): 30.9 ms ± 4.9 ms [User: 22.1 ms, System: 8.3 ms]
Range (min … max): 27.6 ms … 74.6 ms 10000 runs
Benchmark 2: ./target/debug/rust_test
Time (mean ± σ): 26.7 ms ± 4.5 ms [User: 18.6 ms, System: 7.6 ms]
Range (min … max): 24.0 ms … 82.9 ms 10000 runs
Summary
'./target/debug/rust_test' ran
1.16 ± 0.27 times faster than './target/debug/slow'
Note the last line—without the LOGGER check in the filter_fn we are
1.16 times faster!
>> diff --git a/proxmox-rest-server/Cargo.toml b/proxmox-rest-server/Cargo.toml
>> index 5ffde0d6f210..20f43a69a4d0 100644
>> --- a/proxmox-rest-server/Cargo.toml
>> +++ b/proxmox-rest-server/Cargo.toml
>
>This hunk should be in the 2nd patch.
Done. Thanks for the review!
_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
next prev parent reply other threads:[~2024-07-04 9:24 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-01 9:26 [pbs-devel] [PATCH proxmox{, -backup} v7 0/4] proxmox-log introduction Gabriel Goller
2024-07-01 9:26 ` [pbs-devel] [PATCH proxmox v7 1/4] proxmox-log: add tracing infrastructure Gabriel Goller
2024-07-03 14:05 ` Wolfgang Bumiller
2024-07-04 9:24 ` Gabriel Goller [this message]
2024-07-01 9:26 ` [pbs-devel] [PATCH proxmox v7 2/4] enable tracing logger, remove task_log macros Gabriel Goller
2024-07-01 9:26 ` [pbs-devel] [PATCH proxmox-backup v7 3/4] switch from task_log! macro to tracing Gabriel Goller
2024-07-01 9:26 ` [pbs-devel] [PATCH proxmox-backup v7 4/4] api: " Gabriel Goller
2024-07-09 14:20 ` [pbs-devel] [PATCH proxmox{, -backup} v7 0/4] proxmox-log introduction Gabriel Goller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240704092428.2fgqr7sdmwib4p67@luna.proxmox.com \
--to=g.goller@proxmox.com \
--cc=l.wagner@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
--cc=w.bumiller@proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.