objectstore_log/
lib.rs

1//! Logging macros and subscriber initialization for Objectstore.
2//!
3//! This crate provides three things:
4//!
5//! 1. Re-exports of [`tracing`] macros for structured logging — use them qualified as
6//!    `objectstore_log::info!()`. Never import the macros; always qualify at the call site.
7//! 2. [`LoggingConfig`] and [`LogFormat`] for configuring log level and output format, and
8//!    (behind the `init` feature) an [`init`] function to wire up a `tracing-subscriber` stack.
9//!    When built with the `sentry` feature, `init` also attaches a Sentry tracing layer if the
10//!    Sentry client has already been initialized.
11//! 3. Custom level macros (`error!`, `warn!`, etc.) that extend their `tracing` equivalents with
12//!    an optional `!<error>` first argument for ergonomic error field attachment, plus [`event_dyn!`]
13//!    for runtime-dispatched log levels.
14//!
15//! # Usage
16//!
17//! ## Logging macros
18//!
19//! All standard tracing levels are available. Prefix an error expression with `!!` to attach it as
20//! a typed `error` field without a manual cast:
21//!
22//! ```rust
23//! # fn example() -> anyhow::Result<()> {
24//! let err = anyhow::anyhow!("something broke");
25//! objectstore_log::info!("server starting");
26//! objectstore_log::warn!(status = "degraded", "storage unavailable");
27//! objectstore_log::error!(!!err.as_ref(), "fatal startup error");
28//! objectstore_log::warn!(!!err.as_ref(), component = "storage", "retrying");
29//! # Ok(())
30//! # }
31//! ```
32//!
33//! ## `event_dyn!` — dispatch log level at runtime
34//!
35//! ```rust
36//! # use objectstore_log::Level;
37//! let level = Level::WARN;
38//! objectstore_log::event_dyn!(level, "dynamic level message");
39//! objectstore_log::event_dyn!(level, field = "value", "with fields");
40//! ```
41//!
42//! ## Subscriber initialization (requires `init` feature)
43//!
44//! ```rust,ignore
45//! let config = objectstore_log::LoggingConfig::default();
46//! objectstore_log::init(&config);
47//! ```
48//!
49//! ## Span types and span macros
50//!
51//! Types and macros from the underlying [`tracing`] crate that are not re-exported individually
52//! (such as [`tracing::Span`] and [`tracing::debug_span!`]) are accessible through the re-exported
53//! `tracing` module:
54//!
55//! ```rust
56//! use objectstore_log::tracing;
57//! let span: tracing::Span = tracing::debug_span!("my_span");
58//! ```
59
60mod config;
61mod macros;
62#[cfg(feature = "init")]
63mod subscriber;
64
65pub use config::{FormatParseError, LogFormat, LoggingConfig};
66#[cfg(feature = "init")]
67pub use subscriber::init;
68
69/// The underlying [`tracing`] crate, re-exported as a module.
70///
71/// Use this to access types and macros not individually re-exported, such as [`tracing::Span`],
72/// [`tracing::debug_span!`], and [`tracing::field`]:
73///
74/// ```rust
75/// use objectstore_log::tracing;
76/// let _span: tracing::Span = tracing::debug_span!("op");
77/// ```
78pub use tracing;
79pub use tracing::Level;
80pub use tracing::level_filters::LevelFilter;
81
82/// Logs `error` via the tracing subscriber if one is configured, or prints to `stderr` otherwise.
83///
84/// Use this in binary entry points where the subscriber may or may not have been initialized yet,
85/// such as in `main` when a fatal error occurs before or during initialization.
86pub fn ensure_log_error(error: &anyhow::Error) {
87    if Level::ERROR <= tracing::level_filters::STATIC_MAX_LEVEL
88        && Level::ERROR <= LevelFilter::current()
89    {
90        error!(!!error.as_ref());
91    } else {
92        eprintln!("{error:?}");
93    }
94}