Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ jobs:
shell: bash
run: |
set -x
cargo run --features="bridge-log" --example simple_stdout

cargo run --features="bridge-log" --example log_with_logger

cargo run --features="starter-log" --example simple_stdout
cargo run --features="starter-log" --example log_with_logger
cargo run --features="starter-log" --example multiple_dispatches
cargo run --features="starter-log" --example custom_layout_filter
cargo run --features="starter-log" --example json_stdout
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ All notable changes to this project will be documented in this file.
### Breaking changes

* Bump minimum supported Rust version (MSRV) to 1.89.0.
* `Append` has no more `exit` method. Users should compose `logforth::core::default_logger().flush()` with their own graceful shutdown logic.
* `Append` has no more `exit` method. Users should keep a logger handle and compose `Logger::flush()` with their own graceful shutdown logic.
* `Async` appender's `flush` method is now blocking until all buffered logs are flushed by worker threads. Any errors during flushing will be propagated back to the `flush` caller.
* `Record::payload` is now `std::fmt::Arguments` instead of `Cow<'static, str>`.
* `RecordOwned::as_record` has been removed; use `RecordOwned::with` instead. (This is a limitation of Rust as described [here](https://github.com/rust-lang/rust/issues/92698#issuecomment-3311144848).)
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ logforth-layout-text = { version = "0.3.0", path = "layouts/text" }
anyhow = { version = "1.0" }
clap = { version = "4.5.49", features = ["derive"] }
colored = { version = "3.0" }
ctor = { version = "1.0.6" }
fastrace = { version = "0.7" }
fasyslog = { version = "1.0.0" }
insta = { version = "1.43.2" }
Expand Down
8 changes: 2 additions & 6 deletions appenders/file/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,15 @@
//! use logforth_core::record::LevelFilter;
//! use logforth_layout_json::JsonLayout;
//!
//! logforth_bridge_log::setup();
//!
//! let rolling = FileBuilder::new("logs", "app_log")
//! .layout(JsonLayout::default())
//! .rollover_daily()
//! .build()
//! .unwrap();
//!
//! logforth_core::builder()
//! let logger = logforth_core::builder()
//! .dispatch(|d| d.filter(LevelFilter::All).append(rolling))
//! .apply();
//!
//! log::info!("This log will be written to a rolling file.");
//! .build();
//! ```

#![cfg_attr(docsrs, feature(doc_cfg))]
Expand Down
2 changes: 1 addition & 1 deletion appenders/file/src/rolling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ mod tests {

use jiff::Span;
use jiff::Zoned;
use rand::Rng;
use rand::RngExt;
use rand::distr::Alphanumeric;
use tempfile::TempDir;

Expand Down
3 changes: 0 additions & 3 deletions appenders/syslog/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,5 @@ rustls = ["fasyslog/rustls"]
fasyslog = { workspace = true }
logforth-core = { workspace = true }

[dev-dependencies]
log = { workspace = true }

[lints]
workspace = true
6 changes: 2 additions & 4 deletions appenders/syslog/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@
//!
//! let append = SyslogBuilder::tcp_well_known().unwrap().build();
//!
//! logforth_core::builder()
//! let logger = logforth_core::builder()
//! .dispatch(|d| d.filter(LevelFilter::All).append(append))
//! .apply();
//!
//! log::info!("This log will be written to syslog.");
//! .build();
//! ```
#![cfg_attr(docsrs, feature(doc_cfg))]
Expand Down
139 changes: 45 additions & 94 deletions bridges/log/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,75 +17,75 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(missing_docs)]

use std::ops::Deref;
use std::sync::Arc;

use log::Metadata;
use log::Record;
use logforth_core::Logger;
use logforth_core::default_logger;
use logforth_core::kv::Key;
use logforth_core::kv::Value;
use logforth_core::record::FilterCriteria;

fn level_to_level(level: log::Level) -> logforth_core::record::Level {
match level {
log::Level::Error => logforth_core::record::Level::Error,
log::Level::Warn => logforth_core::record::Level::Warn,
log::Level::Info => logforth_core::record::Level::Info,
log::Level::Debug => logforth_core::record::Level::Debug,
log::Level::Trace => logforth_core::record::Level::Trace,
}
}

struct LogCrateLogger(());
/// Adapter to use a `logforth` logger instance as a `log` crate logger.
#[derive(Debug)]
pub struct LogAdapter(Arc<Logger>);

impl log::Log for LogCrateLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
forward_enabled(default_logger(), metadata)
}

fn log(&self, record: &Record) {
forward_log(default_logger(), record);
impl LogAdapter {
/// Create a new `LogAdapter` instance.
pub fn new(logger: Arc<Logger>) -> Self {
Self(logger)
}
}

fn flush(&self) {
default_logger().flush();
impl Clone for LogAdapter {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}

/// Adapter to use a specific `logforth` logger instance as a `log` crate logger.
pub struct LogProxy<'a>(&'a Logger);
impl Deref for LogAdapter {
type Target = Logger;

impl<'a> LogProxy<'a> {
/// Create a new `LogProxy` instance.
pub fn new(logger: &'a Logger) -> Self {
Self(logger)
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<'a> log::Log for LogProxy<'a> {
impl log::Log for LogAdapter {
fn enabled(&self, metadata: &Metadata) -> bool {
forward_enabled(self.0, metadata)
forward_enabled(&self.0, metadata)
}

fn log(&self, record: &Record) {
forward_log(self.0, record);
forward_log(&self.0, record);
}

fn flush(&self) {
self.0.flush();
}
}

/// Owned version of [`LogProxy`].
pub struct OwnedLogProxy(Logger);
/// Owned adapter to use a `logforth` logger instance as a `log` crate logger.
#[derive(Debug)]
pub struct OwnedLogAdapter(Logger);

impl OwnedLogProxy {
/// Create a new `OwnedLogProxy` instance.
impl OwnedLogAdapter {
/// Create a new `OwnedLogAdapter` instance.
pub fn new(logger: Logger) -> Self {
Self(logger)
}
}

impl log::Log for OwnedLogProxy {
impl Deref for OwnedLogAdapter {
type Target = Logger;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl log::Log for OwnedLogAdapter {
fn enabled(&self, metadata: &Metadata) -> bool {
forward_enabled(&self.0, metadata)
}
Expand All @@ -99,6 +99,16 @@ impl log::Log for OwnedLogProxy {
}
}

fn level_to_level(level: log::Level) -> logforth_core::record::Level {
match level {
log::Level::Error => logforth_core::record::Level::Error,
log::Level::Warn => logforth_core::record::Level::Warn,
log::Level::Info => logforth_core::record::Level::Info,
log::Level::Debug => logforth_core::record::Level::Debug,
log::Level::Trace => logforth_core::record::Level::Trace,
}
}

fn forward_enabled(logger: &Logger, metadata: &Metadata) -> bool {
let criteria = FilterCriteria::builder()
.target(metadata.target())
Expand Down Expand Up @@ -163,62 +173,3 @@ fn forward_log(logger: &Logger, record: &Record) {

Logger::log(logger, &builder.build());
}

/// Set up the log crate global logger.
///
/// This function calls [`log::set_logger`] to set up a `LogCrateProxy` and
/// all logs from log crate will be forwarded to `logforth`'s default logger.
///
/// This should be called early in the execution of a Rust program. Any log events that occur
/// before initialization will be ignored.
///
/// This function will set the global maximum log level to `Trace`. To override this, call
/// [`log::set_max_level`] after this function.
///
/// # Errors
///
/// Return an error if the log crate global logger has already been set.
///
/// # Examples
///
/// ```
/// if let Err(err) = logforth_bridge_log::try_setup() {
/// eprintln!("failed to setup log crate: {err}");
/// }
/// ```
pub fn try_setup() -> Result<(), log::SetLoggerError> {
static LOGGER: LogCrateLogger = LogCrateLogger(());
log::set_logger(&LOGGER)?;
log::set_max_level(log::LevelFilter::Trace);
Ok(())
}

/// Set up the log crate global logger.
///
/// This function calls [`log::set_logger`] to set up a `LogCrateProxy` and
/// all logs from log crate will be forwarded to `logforth`'s default logger.
///
/// This should be called early in the execution of a Rust program. Any log events that occur
/// before initialization will be ignored.
///
/// This function will panic if it is called more than once, or if another library has already
/// initialized the log crate global logger.
///
/// This function will set the global maximum log level to `Trace`. To override this, call
/// [`log::set_max_level`] after this function.
///
/// # Panics
///
/// Panic if the log crate global logger has already been set.
///
/// # Examples
///
/// ```
/// logforth_bridge_log::setup();
/// logforth_core::builder().apply()
/// ```
pub fn setup() {
try_setup().expect(
"logforth_bridge_log::setup must be called before the log crate global logger initialized",
)
}
Loading