Skip to main content

espresso_utils/
logging.rs

1use clap::{Parser, ValueEnum};
2pub use hotshot::helpers::FmtSubscriber;
3use hotshot::helpers::{initialize_logging, initialize_logging_on_stderr, initialize_logging_with};
4use log_panics::BacktraceMode;
5use tracing_subscriber::Layer;
6
7/// Controls how backtraces are logged on panic.
8///
9/// The values here match the possible values of `RUST_LOG_FORMAT`, and their corresponding behavior
10/// on backtrace logging is:
11/// * `full`: print a prettified dump of the stack trace and span trace to stdout, optimized for
12///   human readability rather than machine parsing
13/// * `compact`: output the default panic message, with backtraces controlled by `RUST_BACKTRACE`
14/// * `json`: output the panic message and stack trace as a tracing event. This in turn works with
15///   the behavior of the tracing subscriber with `RUST_LOG_FORMAT=json` to output the event in a
16///   machine-parseable, JSON format.
17#[derive(Clone, Copy, Debug, Default, ValueEnum)]
18enum BacktraceLoggingMode {
19    #[default]
20    Full,
21    Compact,
22    Json,
23}
24
25/// Logging configuration.
26#[derive(Clone, Debug, Default, Parser)]
27pub struct Config {
28    #[clap(long, env = "RUST_LOG_FORMAT")]
29    backtrace_mode: Option<BacktraceLoggingMode>,
30}
31
32impl Config {
33    /// Get the logging configuration from the environment.
34    pub fn from_env() -> Self {
35        Self::parse_from(std::iter::empty::<String>())
36    }
37
38    /// Initialize logging and panic handlers based on this configuration.
39    pub fn init(&self) {
40        initialize_logging();
41        self.install_panic_hook();
42    }
43
44    /// Like `init`, but logs to stderr so that stdout carries only the program's own output.
45    pub fn init_on_stderr(&self) {
46        initialize_logging_on_stderr();
47        self.install_panic_hook();
48    }
49
50    /// Like `init`, but also attaches an extra tracing `Layer` (e.g. an OTel bridge).
51    pub fn init_with_otel<L>(&self, otel_layer: Option<L>)
52    where
53        L: Layer<FmtSubscriber> + Send + Sync + 'static,
54    {
55        initialize_logging_with(otel_layer);
56        self.install_panic_hook();
57    }
58
59    fn install_panic_hook(&self) {
60        if let BacktraceLoggingMode::Json = self.backtrace_mode.unwrap_or_default() {
61            log_panics::Config::new()
62                .backtrace_mode(BacktraceMode::Resolved)
63                .install_panic_hook();
64        }
65    }
66}