Skip to content

Commit

Permalink
docs: add docs and some inplace fixes (#21)
Browse files Browse the repository at this point in the history
Signed-off-by: tison <wander4096@gmail.com>
  • Loading branch information
tisonkun authored Aug 1, 2024
1 parent ae6faf5 commit 1617536
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/tisonkun/logforth"
rust-version = "1.71.0"
version = "0.4.0"
version = "0.5.0"

[package.metadata.docs.rs]
all-features = true
Expand Down
9 changes: 6 additions & 3 deletions src/append/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
use std::fmt;

#[cfg(feature = "fastrace")]
pub use fastrace::*;
pub use fastrace::FastraceEvent;
#[cfg(feature = "opentelemetry")]
pub use opentelemetry::*;
pub use stdio::*;
pub use opentelemetry::OpentelemetryLog;
#[cfg(feature = "rolling_file")]
pub use rolling_file::RollingFile;
pub use stdio::Stderr;
pub use stdio::Stdout;

use crate::layout::IdenticalLayout;
use crate::layout::Layout;
Expand Down
68 changes: 53 additions & 15 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ use crate::append::Append;
use crate::filter::Filter;
use crate::filter::FilterResult;
use crate::layout::Layout;

/// A grouped set of appenders, filters, and optional layout.
///
/// The [Logger] facade dispatches log records to one or more [Dispatch] instances.
/// Each [Dispatch] instance contains a set of filters, appenders, and an optional layout.
///
/// `filters` are used to determine whether a log record should be passed to the appenders.
/// `appends` are used to write log records to a destination. Each appender has its own
/// default layout. If the [Dispatch] has a layout, it will be used instead of the default layout.
#[derive(Debug)]
pub struct Dispatch<const LAYOUT: bool = true, const APPEND: bool = true> {
filters: Vec<Filter>,
Expand All @@ -36,6 +45,9 @@ impl Default for Dispatch<false, false> {
}

impl Dispatch<false, false> {
/// Create a new incomplete [Dispatch] instance.
///
/// At least one append must be added to the [Dispatch] before it can be used.
pub fn new() -> Dispatch<false, false> {
Self {
filters: vec![],
Expand All @@ -44,11 +56,14 @@ impl Dispatch<false, false> {
}
}

/// Add a [Filter] to the [Dispatch].
pub fn filter(mut self, filter: impl Into<Filter>) -> Dispatch<false, false> {
self.filters.push(filter.into());
self
}

/// Add the preferred [Layout] to the [Dispatch]. At most one layout can be added to a
/// [Dispatch].
pub fn layout(self, layout: impl Into<Layout>) -> Dispatch<true, false> {
Dispatch {
filters: self.filters,
Expand All @@ -59,10 +74,13 @@ impl Dispatch<false, false> {
}

impl<const LAYOUT: bool, const APPEND: bool> Dispatch<LAYOUT, APPEND> {
pub fn append(self, append: impl Append) -> Dispatch<true, true> {
/// Add an [Append] to the [Dispatch].
pub fn append(mut self, append: impl Append) -> Dispatch<true, true> {
self.appends.push(Box::new(append));

Dispatch {
filters: self.filters,
appends: vec![Box::new(append)],
appends: self.appends,
layout: self.layout,
}
}
Expand All @@ -83,7 +101,6 @@ impl Dispatch {

fn log(&self, record: &Record) -> anyhow::Result<()> {
let layout = self.layout.as_ref();

for append in &self.appends {
match layout {
Some(layout) => layout.format(record, &|record| append.append(record))?,
Expand All @@ -92,7 +109,6 @@ impl Dispatch {
.format(record, &|record| append.append(record))?,
}
}

Ok(())
}

Expand All @@ -103,37 +119,58 @@ impl Dispatch {
}
}

/// A logger facade that dispatches log records to one or more [Dispatch] instances.
///
/// This struct implements [log::Log] to bridge Logforth's logging implementations
/// with the [log] crate.
#[derive(Debug)]
pub struct Logger {
pub struct Logger<const APPEND: bool = true> {
dispatches: Vec<Dispatch>,
}

impl Default for Logger {
impl Default for Logger<false> {
fn default() -> Self {
Self::new()
}
}

impl Logger {
pub fn new() -> Self {
impl Logger<false> {
/// Create a new [Logger] instance.
///
/// The [Logger] instance is incomplete and must have at least one [Dispatch] added to it.
pub fn new() -> Logger<false> {
Self { dispatches: vec![] }
}
}

pub fn dispatch(mut self, dispatch: Dispatch) -> Self {
self.dispatches.push(dispatch);
self
}

impl Logger<true> {
/// Set up the global logger with the [Logger] instance.
///
/// # Errors
///
/// An error is returned if the global logger has already been set.
pub fn apply(self) -> Result<(), log::SetLoggerError> {
log::set_boxed_logger(Box::new(self))?;
log::set_max_level(LevelFilter::Trace);
Ok(())
}
}

impl<const APPEND: bool> Logger<APPEND> {
/// Add a [Dispatch] to the [Logger].
pub fn dispatch(mut self, dispatch: Dispatch) -> Logger<true> {
self.dispatches.push(dispatch);
Logger {
dispatches: self.dispatches,
}
}
}

impl log::Log for Logger {
fn enabled(&self, _: &Metadata) -> bool {
true
fn enabled(&self, metadata: &Metadata) -> bool {
self.dispatches
.iter()
.any(|dispatch| dispatch.enabled(metadata))
}

fn log(&self, record: &Record) {
Expand All @@ -153,6 +190,7 @@ impl log::Log for Logger {
}
}

// TODO(tisonkun): logback and log4j2 support custom error handling (status listener).
fn handle_error(record: &Record, error: anyhow::Error) {
let Err(fallback_error) = write!(
std::io::stderr(),
Expand Down

0 comments on commit 1617536

Please sign in to comment.