From 24e1892e5d4434e6b597b3293fdd648ed7a8dff8 Mon Sep 17 00:00:00 2001 From: Antonio Souza Date: Mon, 26 Jan 2026 18:31:12 -0500 Subject: [PATCH 1/2] add tracing adapter behind optional feature flag Signed-off-by: Antonio Souza --- Cargo.lock | 119 ++++++++++++++++++++++++++++++++++++ Cargo.toml | 11 ++++ README.md | 25 +++++++- examples/tracing_adapter.rs | 15 +++++ src/level.rs | 26 ++++++++ src/lib.rs | 6 ++ src/tracing_adapter.rs | 67 ++++++++++++++++++++ 7 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 examples/tracing_adapter.rs create mode 100644 src/tracing_adapter.rs diff --git a/Cargo.lock b/Cargo.lock index 3b5138c..005de5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,6 +96,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.180" @@ -108,6 +114,15 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -129,6 +144,12 @@ version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "proc-macro2" version = "1.0.106" @@ -153,6 +174,15 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "sheen" version = "0.3.0" @@ -160,6 +190,8 @@ dependencies = [ "chrono", "log", "owo-colors", + "tracing", + "tracing-subscriber", ] [[package]] @@ -168,6 +200,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "syn" version = "2.0.114" @@ -179,12 +217,84 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "wasm-bindgen" version = "0.2.108" @@ -288,3 +398,12 @@ checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml index 5f60565..c5c3f00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,11 +15,22 @@ owo-colors = "4.2.3" chrono = { version = "0.4.43", default-features = false, features = ["clock"] } # Log impl log = { version = "0.4.29", optional = true, features = ["std"] } +# Tracing impl +tracing = { version = "0.1.44", optional = true, default-features = false } +tracing-subscriber = { version = "0.3.22", optional = true, default-features = false, features = ["registry"] } +[features] +tracing = ["dep:tracing", "dep:tracing-subscriber"] [dev-dependencies] log = "0.4.29" +tracing = "0.1.44" +tracing-subscriber = "0.3.22" [[example]] name = "log_adapter" required-features = ["log"] + +[[example]] +name = "tracing_adapter" +required-features = ["tracing"] diff --git a/README.md b/README.md index 46be54f..e8364e6 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ sheen is inspired by [charmbracelet/log](https://github.com/charmbracelet/log), - Builder pattern configuration - Zero config defaults - `log` crate compatibility (optional feature flag) +- `tracing` crate compatibility (optional feature flag) ## Installation @@ -36,12 +37,19 @@ With `log` crate support: sheen = { version = "0.3", features = ["log"] } ``` +With `tracing` crate support: + +```toml +[dependencies] +sheen = { version = "0.3", features = ["tracing"] } +``` + ## Quick Start ```rust fn main() { sheen::init(); - + sheen::info!("Server started", port = 3000); sheen::debug!("Loading config"); sheen::warn!("Cache miss", key = "user_123"); @@ -117,6 +125,21 @@ fn main() { } ``` +## Tracing Crate Integration + +Enable the `tracing` feature to use sheen as a subscriber for the [`tracing`](https://crates.io/crates/tracing) crate. This captures events from any dependency that uses `tracing::info!()`, `tracing::warn!()`, etc. + +```rust +use sheen::{Logger, Level, SheenLayer}; + +fn main() { + SheenLayer::new(Logger::new().level(Level::Trace)).init(); + + tracing::info!("server started"); + tracing::warn!("cache nearly full"); +} +``` + ## Formatters ### Text (default) diff --git a/examples/tracing_adapter.rs b/examples/tracing_adapter.rs new file mode 100644 index 0000000..b9d20f9 --- /dev/null +++ b/examples/tracing_adapter.rs @@ -0,0 +1,15 @@ +use sheen::{Level, Logger, SheenLayer}; +use tracing_subscriber::prelude::*; + +fn main() { + let logger = Logger::new().level(Level::Trace); + let layer = SheenLayer::new(logger); + + tracing_subscriber::registry().with(layer).init(); + + tracing::trace!("starting up"); + tracing::debug!("loading configuration"); + tracing::info!("server listening on port 3000"); + tracing::warn!("cache is nearly full"); + tracing::error!("failed to connect to database"); +} diff --git a/src/level.rs b/src/level.rs index cf3633a..7016af7 100644 --- a/src/level.rs +++ b/src/level.rs @@ -47,6 +47,32 @@ impl From for log::LevelFilter { } } +#[cfg(feature = "tracing")] +impl From for tracing::Level { + fn from(level: Level) -> Self { + match level { + Level::Trace => tracing::Level::TRACE, + Level::Debug => tracing::Level::DEBUG, + Level::Info => tracing::Level::INFO, + Level::Warn => tracing::Level::WARN, + Level::Error => tracing::Level::ERROR, + } + } +} + +#[cfg(feature = "tracing")] +impl From for Level { + fn from(level: tracing::Level) -> Self { + match level { + tracing::Level::TRACE => Level::Trace, + tracing::Level::DEBUG => Level::Debug, + tracing::Level::INFO => Level::Info, + tracing::Level::WARN => Level::Warn, + tracing::Level::ERROR => Level::Error, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/lib.rs b/src/lib.rs index 8388be3..0ab40f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,12 @@ mod macros; #[cfg(feature = "log")] mod log_adapter; +#[cfg(feature = "tracing")] +mod tracing_adapter; + +#[cfg(feature = "tracing")] +pub use tracing_adapter::SheenLayer; + pub use formatter::{Formatter, JsonFormatter, LogFmtFormatter, TextFormatter}; pub use global::{info, init, init_with}; pub use level::Level; diff --git a/src/tracing_adapter.rs b/src/tracing_adapter.rs new file mode 100644 index 0000000..134de0b --- /dev/null +++ b/src/tracing_adapter.rs @@ -0,0 +1,67 @@ +use crate::Logger; + +pub struct SheenLayer { + logger: Logger, +} + +impl SheenLayer { + pub fn new(logger: Logger) -> Self { + Self { logger } + } +} + +struct FieldVisitor { + message: String, + fields: Vec<(String, String)>, +} + +impl FieldVisitor { + fn new() -> Self { + Self { + message: String::new(), + fields: Vec::new(), + } + } +} + +impl tracing::field::Visit for FieldVisitor { + fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) { + if field.name() == "message" { + self.message = format!("{:?}", value); + } else { + self.fields + .push((field.name().to_string(), format!("{:?}", value))); + } + } + + fn record_str(&mut self, field: &tracing::field::Field, value: &str) { + if field.name() == "message" { + self.message = value.to_string(); + } else { + self.fields + .push((field.name().to_string(), value.to_string())); + } + } +} + +impl tracing_subscriber::Layer for SheenLayer { + fn on_event( + &self, + event: &tracing::Event<'_>, + _ctx: tracing_subscriber::layer::Context<'_, S>, + ) { + let mut visitor = FieldVisitor::new(); + event.record(&mut visitor); + + let level = (*event.metadata().level()).into(); + let target = event.metadata().target(); + + let mut extra: Vec<(&str, &dyn std::fmt::Debug)> = + vec![("target", &target as &dyn std::fmt::Debug)]; + for (k, v) in &visitor.fields { + extra.push((k.as_str(), v as &dyn std::fmt::Debug)); + } + + self.logger.log(level, &visitor.message, &extra); + } +} From 12586e52f30e73aa5271f73cb4a4c0417bfa1d6d Mon Sep 17 00:00:00 2001 From: Antonio Souza Date: Mon, 26 Jan 2026 18:40:41 -0500 Subject: [PATCH 2/2] wrap registry setup for tracing Signed-off-by: Antonio Souza --- examples/tracing_adapter.rs | 6 +----- src/tracing_adapter.rs | 5 +++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/tracing_adapter.rs b/examples/tracing_adapter.rs index b9d20f9..e6b7d81 100644 --- a/examples/tracing_adapter.rs +++ b/examples/tracing_adapter.rs @@ -1,11 +1,7 @@ use sheen::{Level, Logger, SheenLayer}; -use tracing_subscriber::prelude::*; fn main() { - let logger = Logger::new().level(Level::Trace); - let layer = SheenLayer::new(logger); - - tracing_subscriber::registry().with(layer).init(); + SheenLayer::new(Logger::new().level(Level::Trace)).init(); tracing::trace!("starting up"); tracing::debug!("loading configuration"); diff --git a/src/tracing_adapter.rs b/src/tracing_adapter.rs index 134de0b..f722cb1 100644 --- a/src/tracing_adapter.rs +++ b/src/tracing_adapter.rs @@ -8,6 +8,11 @@ impl SheenLayer { pub fn new(logger: Logger) -> Self { Self { logger } } + + pub fn init(self) { + use tracing_subscriber::prelude::*; + tracing_subscriber::registry().with(self).init(); + } } struct FieldVisitor {