Skip to content

Commit

Permalink
feat: docs and doctest
Browse files Browse the repository at this point in the history
  • Loading branch information
loocapro committed Dec 15, 2023
1 parent d687fe5 commit b10012f
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 82 deletions.
2 changes: 1 addition & 1 deletion crates/tracing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ tracing-journald = "0.3"
tracing-logfmt = "0.3.3"
rolling-file = "0.2.0"
eyre.workspace = true
clap.workspace = true
clap = { workspace = true, features = ["derive"] }
3 changes: 1 addition & 2 deletions crates/tracing/src/formatter.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::BoxedLayer;
use clap::ValueEnum;
use std::{fmt, fmt::Display};
use tracing_appender::non_blocking::NonBlocking;
use tracing_subscriber::{EnvFilter, Layer, Registry};

use crate::BoxedLayer;

/// Represents the logging format.
///
/// This enum defines the supported formats for logging output.
Expand Down
27 changes: 11 additions & 16 deletions crates/tracing/src/layers.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use std::path::{Path, PathBuf};

use rolling_file::{RollingConditionBasic, RollingFileAppender};
use tracing::Subscriber;
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::{filter::Directive, registry::LookupSpan, EnvFilter, Layer, Registry};
use tracing_subscriber::{filter::Directive, EnvFilter, Layer, Registry};

use crate::{formatter::LogFormat, BoxedLayer, FileWorkerGuard};

Expand All @@ -27,7 +26,7 @@ fn build_env_filter(
directives: &str,
) -> eyre::Result<EnvFilter> {
let env_filter = if let Some(default_directive) = default_directive {
EnvFilter::builder().with_default_directive(default_directive.into()).from_env_lossy()
EnvFilter::builder().with_default_directive(default_directive).from_env_lossy()
} else {
EnvFilter::builder().from_env_lossy()
};
Expand All @@ -44,18 +43,18 @@ fn build_env_filter(
///
/// `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 struct Layers {
pub(crate) struct Layers {
inner: Vec<BoxedLayer<Registry>>,
}

impl Layers {
/// Creates a new `Layers` instance.
pub fn new() -> Self {
pub(crate) fn new() -> Self {
Self { inner: vec![] }
}

/// Consumes the `Layers` instance, returning the inner vector of layers.
pub fn into_inner(self) -> Vec<BoxedLayer<Registry>> {
pub(crate) fn into_inner(self) -> Vec<BoxedLayer<Registry>> {
self.inner
}

Expand All @@ -66,9 +65,9 @@ impl Layers {
///
/// # Returns
/// An `eyre::Result<()>` indicating the success or failure of the operation.
pub fn journald(&mut self, filter: &str) -> eyre::Result<()> {
pub(crate) fn journald(&mut self, filter: &str) -> eyre::Result<()> {
let journald_filter = build_env_filter(None, filter)?;
let layer = tracing_journald::layer().unwrap().with_filter(journald_filter).boxed();
let layer = tracing_journald::layer()?.with_filter(journald_filter).boxed();
self.inner.push(layer);
Ok(())
}
Expand All @@ -86,17 +85,13 @@ impl Layers {
///
/// # Returns
/// An `eyre::Result<()>` indicating the success or failure of the operation.
pub fn stdout<S>(
pub(crate) fn stdout(
&mut self,
format: LogFormat,
directive: Directive,
filter: &str,
color: Option<String>,
) -> eyre::Result<()>
where
S: Subscriber,
for<'a> S: LookupSpan<'a>,
{
) -> eyre::Result<()> {
let filter = build_env_filter(Some(directive), filter)?;
let layer = format.apply(filter, color, None);
self.inner.push(layer.boxed());
Expand All @@ -112,14 +107,14 @@ impl Layers {
///
/// # Returns
/// An `eyre::Result<FileWorkerGuard>` representing the file logging worker.
pub fn file(
pub(crate) fn file(
&mut self,
format: LogFormat,
filter: String,
file_info: FileInfo,
) -> eyre::Result<FileWorkerGuard> {
let log_dir = file_info.create_log_dir();
let (writer, guard) = file_info.create_log_writer(&log_dir);
let (writer, guard) = file_info.create_log_writer(log_dir);

let file_filter = build_env_filter(None, &filter)?;
let layer = format.apply(file_filter, None, Some(writer));
Expand Down
39 changes: 39 additions & 0 deletions crates/tracing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,47 @@ use tracing_subscriber::{
pub use tracing;
pub use tracing_subscriber;

/// The `tracer` module provides functionalities for setting up and configuring logging.
///
/// 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.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use reth_tracing::{
/// tracer::{LayerInfo, Tracer},
/// tracing::level_filters::LevelFilter,
/// LogFormat,
/// };
///
/// fn main() -> eyre::Result<()> {
/// let tracer = Tracer::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.
pub mod tracer;

// Re-export LogFormat
pub use formatter::LogFormat;

mod formatter;
mod layers;

Expand Down
141 changes: 78 additions & 63 deletions crates/tracing/src/tracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,17 @@ use crate::{
};
use tracing::level_filters::LevelFilter;
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::{
filter::Directive, layer::SubscriberExt, util::SubscriberInitExt, Registry,
};

/// Configuration for a logging layer.
///
/// This struct holds configuration parameters for a tracing layer, including
/// the format, filtering directives, optional coloring, and directive.
#[derive(Debug)]
pub struct LayerConfig {
format: LogFormat,
filters: String,
color: Option<String>,
directive: Directive,
}

impl LayerConfig {
/// Constructs a new `LayerConfig`.
///
/// # 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.
/// * `directive` - Directive for filtering log messages.
/// * `filters` - Additional filtering parameters as a string.
/// * `color` - Optional color configuration for the log messages.
pub fn new(
format: LogFormat,
directive: Directive,
filters: String,
color: Option<String>,
) -> Self {
Self { format, directive, filters, color }
}
}
impl Default for LayerConfig {
/// Provides default values for `LayerConfig`.
///
/// 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: "".to_string(),
color: None,
}
}
}
use tracing_subscriber::{filter::Directive, 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)]
pub struct Tracer {
stdout: LayerConfig,
journald: Option<LayerConfig>,
file: Option<(LayerConfig, FileInfo)>,
stdout: LayerInfo,
journald: Option<String>,
file: Option<(LayerInfo, FileInfo)>,
}

impl Tracer {
Expand All @@ -72,25 +23,34 @@ impl Tracer {
/// Initializes with default stdout layer configuration.
/// Journald and file layers are not set by default.
pub fn new() -> Self {
Self { stdout: LayerConfig::default(), journald: None, file: None }
Self { stdout: LayerInfo::default(), journald: None, file: None }
}

/// 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
}

/// Sets the journald layer configuration.
/// Sets the journald layer filter.
///
/// # Arguments
/// * `config` - The `LayerConfig` to use for the journald layer.
pub fn with_journald(mut self, config: LayerConfig) -> Self {
self.journald = Some(config);
/// * `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 `LayerConfig` to use for the file layer.
/// * `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: LayerConfig, file_info: FileInfo) -> Self {
pub fn with_file(mut self, config: LayerInfo, file_info: FileInfo) -> Self {
self.file = Some((config, file_info));
self
}
Expand All @@ -100,22 +60,24 @@ impl Tracer {
/// 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.
#[must_use]
#[must_use = "This method must be called to initialize the logging system."]
pub fn init(self) -> eyre::Result<Option<WorkerGuard>> {
let mut layers = Layers::new();

layers.stdout::<Registry>(
layers.stdout(
self.stdout.format,
self.stdout.directive,
&self.stdout.filters,
self.stdout.color,
)?;

if let Some(config) = self.journald {
layers.journald(&config.filters)?;
layers.journald(&config)?;
}

let file_guard = if let Some((config, file_info)) = self.file {
Expand All @@ -128,3 +90,56 @@ impl Tracer {
Ok(file_guard)
}
}

impl Default for Tracer {
fn default() -> Self {
Self::new()
}
}

/// Configuration for a logging layer.
///
/// This struct holds configuration parameters for a tracing layer, including
/// the format, filtering directives, optional coloring, and directive.
#[derive(Debug)]
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: "".to_string(),
color: None,
}
}
}

0 comments on commit b10012f

Please sign in to comment.