mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
Json structured logs (#5784)
Co-authored-by: Alexey Shekhirin <a.shekhirin@gmail.com>
This commit is contained in:
@ -13,7 +13,10 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
tracing.workspace = true
|
||||
tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt"] }
|
||||
tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt", "json"] }
|
||||
tracing-appender.workspace = true
|
||||
tracing-journald = "0.3"
|
||||
tracing-logfmt = "0.3.3"
|
||||
rolling-file = "0.2.0"
|
||||
eyre.workspace = true
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
86
crates/tracing/src/formatter.rs
Normal file
86
crates/tracing/src/formatter.rs
Normal file
@ -0,0 +1,86 @@
|
||||
use crate::layers::BoxedLayer;
|
||||
use clap::ValueEnum;
|
||||
use std::{fmt, fmt::Display};
|
||||
use tracing_appender::non_blocking::NonBlocking;
|
||||
use tracing_subscriber::{EnvFilter, Layer, Registry};
|
||||
|
||||
/// Represents the logging format.
|
||||
///
|
||||
/// This enum defines the supported formats for logging output.
|
||||
/// It is used to configure the format layer of a tracing subscriber.
|
||||
#[derive(Debug, Copy, Clone, ValueEnum, Eq, PartialEq)]
|
||||
pub enum LogFormat {
|
||||
/// Represents JSON formatting for logs.
|
||||
/// This format outputs log records as JSON objects,
|
||||
/// making it suitable for structured logging.
|
||||
Json,
|
||||
|
||||
/// Represents logfmt (key=value) formatting for logs.
|
||||
/// This format is concise and human-readable,
|
||||
/// typically used in command-line applications.
|
||||
LogFmt,
|
||||
|
||||
/// Represents terminal-friendly formatting for logs.
|
||||
Terminal,
|
||||
}
|
||||
|
||||
impl LogFormat {
|
||||
/// Applies the specified logging format to create a new layer.
|
||||
///
|
||||
/// This method constructs a tracing layer with the selected format,
|
||||
/// along with additional configurations for filtering and output.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `filter` - An `EnvFilter` used to determine which log records to output.
|
||||
/// * `color` - An optional string that enables or disables ANSI color codes in the logs.
|
||||
/// * `file_writer` - An optional `NonBlocking` writer for directing logs to a file.
|
||||
///
|
||||
/// # Returns
|
||||
/// A `BoxedLayer<Registry>` that can be added to a tracing subscriber.
|
||||
pub fn apply(
|
||||
&self,
|
||||
filter: EnvFilter,
|
||||
color: Option<String>,
|
||||
file_writer: Option<NonBlocking>,
|
||||
) -> BoxedLayer<Registry> {
|
||||
let ansi = if let Some(color) = color {
|
||||
std::env::var("RUST_LOG_STYLE").map(|val| val != "never").unwrap_or(color != "never")
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let target = std::env::var("RUST_LOG_TARGET").map(|val| val != "0").unwrap_or(true);
|
||||
|
||||
match self {
|
||||
LogFormat::Json => {
|
||||
let layer =
|
||||
tracing_subscriber::fmt::layer().json().with_ansi(ansi).with_target(target);
|
||||
|
||||
if let Some(writer) = file_writer {
|
||||
layer.with_writer(writer).with_filter(filter).boxed()
|
||||
} else {
|
||||
layer.with_filter(filter).boxed()
|
||||
}
|
||||
}
|
||||
LogFormat::LogFmt => tracing_logfmt::layer().with_filter(filter).boxed(),
|
||||
LogFormat::Terminal => {
|
||||
let layer = tracing_subscriber::fmt::layer().with_ansi(ansi).with_target(target);
|
||||
|
||||
if let Some(writer) = file_writer {
|
||||
layer.with_writer(writer).with_filter(filter).boxed()
|
||||
} else {
|
||||
layer.with_filter(filter).boxed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LogFormat {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
LogFormat::Json => write!(f, "json"),
|
||||
LogFormat::LogFmt => write!(f, "logfmt"),
|
||||
LogFormat::Terminal => write!(f, "terminal"),
|
||||
}
|
||||
}
|
||||
}
|
||||
180
crates/tracing/src/layers.rs
Normal file
180
crates/tracing/src/layers.rs
Normal file
@ -0,0 +1,180 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rolling_file::{RollingConditionBasic, RollingFileAppender};
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::{filter::Directive, EnvFilter, Layer, Registry};
|
||||
|
||||
use crate::formatter::LogFormat;
|
||||
|
||||
/// A worker guard returned by the file layer.
|
||||
///
|
||||
/// When a guard is dropped, all events currently in-memory are flushed to the log file this guard
|
||||
/// belongs to.
|
||||
pub type FileWorkerGuard = tracing_appender::non_blocking::WorkerGuard;
|
||||
|
||||
/// A boxed tracing [Layer].
|
||||
pub(crate) type BoxedLayer<S> = Box<dyn Layer<S> + Send + Sync>;
|
||||
|
||||
const RETH_LOG_FILE_NAME: &str = "reth.log";
|
||||
|
||||
/// Default [directives](Directive) for [EnvFilter] which disables high-frequency debug logs from
|
||||
/// `hyper` and `trust-dns`
|
||||
const DEFAULT_ENV_FILTER_DIRECTIVES: [&str; 3] =
|
||||
["hyper::proto::h1=off", "trust_dns_proto=off", "trust_dns_resolver=off"];
|
||||
|
||||
/// Manages the collection of layers for a tracing subscriber.
|
||||
///
|
||||
/// `Layers` acts as a container for different logging layers such as stdout, file, or journald.
|
||||
/// Each layer can be configured separately and then combined into a tracing subscriber.
|
||||
pub(crate) struct Layers {
|
||||
inner: Vec<BoxedLayer<Registry>>,
|
||||
}
|
||||
|
||||
impl Layers {
|
||||
/// Creates a new `Layers` instance.
|
||||
pub(crate) fn new() -> Self {
|
||||
Self { inner: vec![] }
|
||||
}
|
||||
|
||||
/// Consumes the `Layers` instance, returning the inner vector of layers.
|
||||
pub(crate) fn into_inner(self) -> Vec<BoxedLayer<Registry>> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
/// Adds a journald layer to the layers collection.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `filter` - A string containing additional filter directives for this layer.
|
||||
///
|
||||
/// # Returns
|
||||
/// An `eyre::Result<()>` indicating the success or failure of the operation.
|
||||
pub(crate) fn journald(&mut self, filter: &str) -> eyre::Result<()> {
|
||||
let journald_filter = build_env_filter(None, filter)?;
|
||||
let layer = tracing_journald::layer()?.with_filter(journald_filter).boxed();
|
||||
self.inner.push(layer);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds a stdout layer with specified formatting and filtering.
|
||||
///
|
||||
/// # Type Parameters
|
||||
/// * `S` - The type of subscriber that will use these layers.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `format` - The log message format.
|
||||
/// * `directive` - Directive for the default logging level.
|
||||
/// * `filter` - Additional filter directives as a string.
|
||||
/// * `color` - Optional color configuration for the log messages.
|
||||
///
|
||||
/// # Returns
|
||||
/// An `eyre::Result<()>` indicating the success or failure of the operation.
|
||||
pub(crate) fn stdout(
|
||||
&mut self,
|
||||
format: LogFormat,
|
||||
directive: Directive,
|
||||
filter: &str,
|
||||
color: Option<String>,
|
||||
) -> eyre::Result<()> {
|
||||
let filter = build_env_filter(Some(directive), filter)?;
|
||||
let layer = format.apply(filter, color, None);
|
||||
self.inner.push(layer.boxed());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds a file logging layer to the layers collection.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `format` - The format for log messages.
|
||||
/// * `filter` - Additional filter directives as a string.
|
||||
/// * `file_info` - Information about the log file including path and rotation strategy.
|
||||
///
|
||||
/// # Returns
|
||||
/// An `eyre::Result<FileWorkerGuard>` representing the file logging worker.
|
||||
pub(crate) fn file(
|
||||
&mut self,
|
||||
format: LogFormat,
|
||||
filter: &str,
|
||||
file_info: FileInfo,
|
||||
) -> eyre::Result<FileWorkerGuard> {
|
||||
let (writer, guard) = file_info.create_log_writer();
|
||||
let file_filter = build_env_filter(None, filter)?;
|
||||
let layer = format.apply(file_filter, None, Some(writer));
|
||||
self.inner.push(layer);
|
||||
Ok(guard)
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds configuration information for file logging.
|
||||
///
|
||||
/// Contains details about the log file's path, name, size, and rotation strategy.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileInfo {
|
||||
dir: PathBuf,
|
||||
file_name: String,
|
||||
max_size_bytes: u64,
|
||||
max_files: usize,
|
||||
}
|
||||
|
||||
impl FileInfo {
|
||||
/// Creates a new `FileInfo` instance.
|
||||
pub fn new(dir: PathBuf, max_size_bytes: u64, max_files: usize) -> Self {
|
||||
Self { dir, file_name: RETH_LOG_FILE_NAME.to_string(), max_size_bytes, max_files }
|
||||
}
|
||||
|
||||
/// Creates the log directory if it doesn't exist.
|
||||
///
|
||||
/// # Returns
|
||||
/// A reference to the path of the log directory.
|
||||
fn create_log_dir(&self) -> &Path {
|
||||
let log_dir: &Path = self.dir.as_ref();
|
||||
if !log_dir.exists() {
|
||||
std::fs::create_dir_all(log_dir).expect("Could not create log directory");
|
||||
}
|
||||
log_dir
|
||||
}
|
||||
|
||||
/// Creates a non-blocking writer for the log file.
|
||||
///
|
||||
/// # Returns
|
||||
/// A tuple containing the non-blocking writer and its associated worker guard.
|
||||
fn create_log_writer(&self) -> (tracing_appender::non_blocking::NonBlocking, WorkerGuard) {
|
||||
let log_dir = self.create_log_dir();
|
||||
let (writer, guard) = tracing_appender::non_blocking(
|
||||
RollingFileAppender::new(
|
||||
log_dir.join(&self.file_name),
|
||||
RollingConditionBasic::new().max_size(self.max_size_bytes),
|
||||
self.max_files,
|
||||
)
|
||||
.expect("Could not initialize file logging"),
|
||||
);
|
||||
(writer, guard)
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an environment filter for logging.
|
||||
///
|
||||
/// The events are filtered by `default_directive`, unless overridden by `RUST_LOG`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `default_directive` - An optional `Directive` that sets the default directive.
|
||||
/// * `directives` - Additional directives as a comma-separated string.
|
||||
///
|
||||
/// # Returns
|
||||
/// An `eyre::Result<EnvFilter>` that can be used to configure a tracing subscriber.
|
||||
fn build_env_filter(
|
||||
default_directive: Option<Directive>,
|
||||
directives: &str,
|
||||
) -> eyre::Result<EnvFilter> {
|
||||
let env_filter = if let Some(default_directive) = default_directive {
|
||||
EnvFilter::builder().with_default_directive(default_directive).from_env_lossy()
|
||||
} else {
|
||||
EnvFilter::builder().from_env_lossy()
|
||||
};
|
||||
|
||||
DEFAULT_ENV_FILTER_DIRECTIVES
|
||||
.into_iter()
|
||||
.chain(directives.split(','))
|
||||
.try_fold(env_filter, |env_filter, directive| {
|
||||
Ok(env_filter.add_directive(directive.parse()?))
|
||||
})
|
||||
}
|
||||
@ -1,12 +1,39 @@
|
||||
//! Reth tracing subscribers and utilities.
|
||||
//! The `tracing` module provides functionalities for setting up and configuring logging.
|
||||
//!
|
||||
//! Contains a standardized set of layers:
|
||||
//! It includes structures and functions to create and manage various logging layers: stdout,
|
||||
//! file, or journald. The module's primary entry point is the `Tracer` struct, which can be
|
||||
//! configured to use different logging formats and destinations. If no layer is specified, it will
|
||||
//! default to stdout.
|
||||
//!
|
||||
//! - [`stdout()`]
|
||||
//! - [`file()`]
|
||||
//! - [`journald()`]
|
||||
//! # Examples
|
||||
//!
|
||||
//! As well as a simple way to initialize a subscriber: [`init`].
|
||||
//! Basic usage:
|
||||
//!
|
||||
//! ```
|
||||
//! use reth_tracing::{
|
||||
//! LayerInfo, RethTracer, Tracer,
|
||||
//! tracing::level_filters::LevelFilter,
|
||||
//! LogFormat,
|
||||
//! };
|
||||
//!
|
||||
//! fn main() -> eyre::Result<()> {
|
||||
//! let tracer = RethTracer::new().with_stdout(LayerInfo::new(
|
||||
//! LogFormat::Json,
|
||||
//! "debug".to_string(),
|
||||
//! LevelFilter::INFO.into(),
|
||||
//! None,
|
||||
//! ));
|
||||
//!
|
||||
//! tracer.init()?;
|
||||
//!
|
||||
//! // Your application logic here
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This example sets up a tracer with JSON format logging for journald and terminal-friendly
|
||||
//! format for file logging.
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||
@ -15,120 +42,184 @@
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
|
||||
use rolling_file::{RollingConditionBasic, RollingFileAppender};
|
||||
use std::path::Path;
|
||||
use tracing::Subscriber;
|
||||
use tracing_subscriber::{
|
||||
filter::Directive, prelude::*, registry::LookupSpan, EnvFilter, Layer, Registry,
|
||||
};
|
||||
use tracing_subscriber::{filter::Directive, EnvFilter};
|
||||
|
||||
// Re-export tracing crates
|
||||
pub use tracing;
|
||||
pub use tracing_subscriber;
|
||||
|
||||
/// A boxed tracing [Layer].
|
||||
pub type BoxedLayer<S> = Box<dyn Layer<S> + Send + Sync>;
|
||||
// Re-export LogFormat
|
||||
pub use formatter::LogFormat;
|
||||
pub use layers::{FileInfo, FileWorkerGuard};
|
||||
|
||||
/// Initializes a new [Subscriber] based on the given layers.
|
||||
pub fn init(layers: Vec<BoxedLayer<Registry>>) {
|
||||
// To avoid panicking in tests, we silently fail if we cannot initialize the subscriber.
|
||||
let _ = tracing_subscriber::registry().with(layers).try_init();
|
||||
mod formatter;
|
||||
mod layers;
|
||||
|
||||
use crate::layers::Layers;
|
||||
use tracing::level_filters::LevelFilter;
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
/// Tracer for application logging.
|
||||
///
|
||||
/// Manages the configuration and initialization of logging layers,
|
||||
/// including standard output, optional journald, and optional file logging.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RethTracer {
|
||||
stdout: LayerInfo,
|
||||
journald: Option<String>,
|
||||
file: Option<(LayerInfo, FileInfo)>,
|
||||
}
|
||||
|
||||
/// Builds a new tracing layer that writes to stdout.
|
||||
///
|
||||
/// The events are filtered by `default_directive`, unless overridden by `RUST_LOG`.
|
||||
///
|
||||
/// Colors can be disabled with `RUST_LOG_STYLE=never`, and event targets can be displayed with
|
||||
/// `RUST_LOG_TARGET=1`.
|
||||
pub fn stdout<S>(default_directive: impl Into<Directive>, color: &str) -> BoxedLayer<S>
|
||||
where
|
||||
S: Subscriber,
|
||||
for<'a> S: LookupSpan<'a>,
|
||||
{
|
||||
// TODO: Auto-detect
|
||||
let with_ansi =
|
||||
std::env::var("RUST_LOG_STYLE").map(|val| val != "never").unwrap_or(color != "never");
|
||||
let with_target = std::env::var("RUST_LOG_TARGET").map(|val| val != "0").unwrap_or(true);
|
||||
|
||||
let filter =
|
||||
EnvFilter::builder().with_default_directive(default_directive.into()).from_env_lossy();
|
||||
|
||||
tracing_subscriber::fmt::layer()
|
||||
.with_ansi(with_ansi)
|
||||
.with_target(with_target)
|
||||
.with_filter(filter)
|
||||
.boxed()
|
||||
}
|
||||
|
||||
/// Builds a new tracing layer that appends to a log file.
|
||||
///
|
||||
/// The events are filtered by `filter`.
|
||||
///
|
||||
/// The boxed layer and a guard is returned. When the guard is dropped the buffer for the log
|
||||
/// file is immediately flushed to disk. Any events after the guard is dropped may be missed.
|
||||
#[must_use = "tracing guard must be kept alive to flush events to disk"]
|
||||
pub fn file<S>(
|
||||
filter: EnvFilter,
|
||||
dir: impl AsRef<Path>,
|
||||
file_name: impl AsRef<Path>,
|
||||
max_size_bytes: u64,
|
||||
max_files: usize,
|
||||
) -> (BoxedLayer<S>, tracing_appender::non_blocking::WorkerGuard)
|
||||
where
|
||||
S: Subscriber,
|
||||
for<'a> S: LookupSpan<'a>,
|
||||
{
|
||||
// Create log dir if it doesn't exist (RFA doesn't do this for us)
|
||||
let log_dir = dir.as_ref();
|
||||
if !log_dir.exists() {
|
||||
std::fs::create_dir_all(log_dir).expect("Could not create log directory");
|
||||
impl RethTracer {
|
||||
/// Constructs a new `Tracer` with default settings.
|
||||
///
|
||||
/// Initializes with default stdout layer configuration.
|
||||
/// Journald and file layers are not set by default.
|
||||
pub fn new() -> Self {
|
||||
Self { stdout: LayerInfo::default(), journald: None, file: None }
|
||||
}
|
||||
|
||||
// Create layer
|
||||
let (writer, guard) = tracing_appender::non_blocking(
|
||||
RollingFileAppender::new(
|
||||
log_dir.join(file_name.as_ref()),
|
||||
RollingConditionBasic::new().max_size(max_size_bytes),
|
||||
max_files,
|
||||
)
|
||||
.expect("Could not initialize file logging"),
|
||||
);
|
||||
let layer = tracing_subscriber::fmt::layer()
|
||||
.with_ansi(false)
|
||||
.with_writer(writer)
|
||||
.with_filter(filter)
|
||||
.boxed();
|
||||
/// Sets a custom configuration for the stdout layer.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `config` - The `LayerInfo` to use for the stdout layer.
|
||||
pub fn with_stdout(mut self, config: LayerInfo) -> Self {
|
||||
self.stdout = config;
|
||||
self
|
||||
}
|
||||
|
||||
(layer, guard)
|
||||
/// Sets the journald layer filter.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `filter` - The `filter` to use for the journald layer.
|
||||
pub fn with_journald(mut self, filter: String) -> Self {
|
||||
self.journald = Some(filter);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the file layer configuration and associated file info.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `config` - The `LayerInfo` to use for the file layer.
|
||||
/// * `file_info` - The `FileInfo` containing details about the log file.
|
||||
pub fn with_file(mut self, config: LayerInfo, file_info: FileInfo) -> Self {
|
||||
self.file = Some((config, file_info));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A worker guard returned by [`file()`].
|
||||
///
|
||||
/// When a guard is dropped, all events currently in-memory are flushed to the log file this guard
|
||||
/// belongs to.
|
||||
pub type FileWorkerGuard = tracing_appender::non_blocking::WorkerGuard;
|
||||
|
||||
/// Builds a new tracing layer that writes events to journald.
|
||||
///
|
||||
/// The events are filtered by `filter`.
|
||||
///
|
||||
/// If the layer cannot connect to journald for any reason this function will return an error.
|
||||
pub fn journald<S>(filter: EnvFilter) -> std::io::Result<BoxedLayer<S>>
|
||||
where
|
||||
S: Subscriber,
|
||||
for<'a> S: LookupSpan<'a>,
|
||||
{
|
||||
Ok(tracing_journald::layer()?.with_filter(filter).boxed())
|
||||
impl Default for RethTracer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes a tracing subscriber for tests.
|
||||
/// Configuration for a logging layer.
|
||||
///
|
||||
/// The filter is configurable via `RUST_LOG`.
|
||||
/// This struct holds configuration parameters for a tracing layer, including
|
||||
/// the format, filtering directives, optional coloring, and directive.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LayerInfo {
|
||||
format: LogFormat,
|
||||
filters: String,
|
||||
directive: Directive,
|
||||
color: Option<String>,
|
||||
}
|
||||
|
||||
impl LayerInfo {
|
||||
/// Constructs a new `LayerInfo`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `format` - Specifies the format for log messages. Possible values are:
|
||||
/// - `LogFormat::Json` for JSON formatting.
|
||||
/// - `LogFormat::LogFmt` for logfmt (key=value) formatting.
|
||||
/// - `LogFormat::Terminal` for human-readable, terminal-friendly formatting.
|
||||
/// * `filters` - Additional filtering parameters as a string.
|
||||
/// * `directive` - Directive for filtering log messages.
|
||||
/// * `color` - Optional color configuration for the log messages.
|
||||
pub fn new(
|
||||
format: LogFormat,
|
||||
filters: String,
|
||||
directive: Directive,
|
||||
color: Option<String>,
|
||||
) -> Self {
|
||||
Self { format, directive, filters, color }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LayerInfo {
|
||||
/// Provides default values for `LayerInfo`.
|
||||
///
|
||||
/// By default, it uses terminal format, INFO level filter,
|
||||
/// no additional filters, and no color configuration.
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
format: LogFormat::Terminal,
|
||||
directive: LevelFilter::INFO.into(),
|
||||
filters: "debug".to_string(),
|
||||
color: Some("always".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait defining a general interface for logging configuration.
|
||||
///
|
||||
/// # Note
|
||||
/// The `Tracer` trait provides a standardized way to initialize logging configurations
|
||||
/// in an application. Implementations of this trait can specify different logging setups,
|
||||
/// such as standard output logging, file logging, journald logging, or custom logging
|
||||
/// configurations tailored for specific environments (like testing).
|
||||
pub trait Tracer {
|
||||
/// Initialize the logging configuration.
|
||||
/// # Returns
|
||||
/// An `eyre::Result` which is `Ok` with an optional `WorkerGuard` if a file layer is used,
|
||||
/// or an `Err` in case of an error during initialization.
|
||||
fn init(self) -> eyre::Result<Option<WorkerGuard>>;
|
||||
}
|
||||
|
||||
impl Tracer for RethTracer {
|
||||
/// Initializes the logging system based on the configured layers.
|
||||
///
|
||||
/// This method sets up the global tracing subscriber with the specified
|
||||
/// stdout, journald, and file layers.
|
||||
///
|
||||
/// The default layer is stdout.
|
||||
///
|
||||
/// # Returns
|
||||
/// An `eyre::Result` which is `Ok` with an optional `WorkerGuard` if a file layer is used,
|
||||
/// or an `Err` in case of an error during initialization.
|
||||
fn init(self) -> eyre::Result<Option<WorkerGuard>> {
|
||||
let mut layers = Layers::new();
|
||||
|
||||
layers.stdout(
|
||||
self.stdout.format,
|
||||
self.stdout.directive,
|
||||
&self.stdout.filters,
|
||||
self.stdout.color,
|
||||
)?;
|
||||
|
||||
if let Some(config) = self.journald {
|
||||
layers.journald(&config)?;
|
||||
}
|
||||
|
||||
let file_guard = if let Some((config, file_info)) = self.file {
|
||||
Some(layers.file(config.format, &config.filters, file_info)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
tracing_subscriber::registry().with(layers.into_inner()).init();
|
||||
Ok(file_guard)
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes a tracing subscriber for tests.
|
||||
///
|
||||
/// The subscriber will silently fail if it could not be installed.
|
||||
/// The filter is configurable via `RUST_LOG`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The subscriber will silently fail if it could not be installed.
|
||||
pub fn init_test_tracing() {
|
||||
let _ = tracing_subscriber::fmt()
|
||||
.with_env_filter(EnvFilter::from_default_env())
|
||||
|
||||
Reference in New Issue
Block a user