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
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sheen"
version = "0.2.0"
version = "0.3.0"
edition = "2024"
license = "MIT"
repository = "https://github.com/arferreira/sheen"
Expand All @@ -13,3 +13,13 @@ categories = ["development-tools::debugging"]
[dependencies]
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"] }


[dev-dependencies]
log = "0.4.29"

[[example]]
name = "log_adapter"
required-features = ["log"]
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,20 @@ sheen is inspired by [charmbracelet/log](https://github.com/charmbracelet/log),
- TTY detection (auto-disables colors when piped)
- Builder pattern configuration
- Zero config defaults
- `log` crate compatibility (optional feature flag)

## Installation

```toml
[dependencies]
sheen = "0.2"
sheen = "0.3"
```

With `log` crate support:

```toml
[dependencies]
sheen = { version = "0.3", features = ["log"] }
```

## Quick Start
Expand Down Expand Up @@ -90,6 +98,25 @@ Output:
14:32:15 INFO completed request_id="abc123" status=200
```

## Log Crate Integration

Enable the `log` feature to use sheen as a backend for the [`log`](https://crates.io/crates/log) crate. This captures logs from any dependency that uses `log::info!()`, `log::warn!()`, etc.

```rust
use sheen::{Logger, Level};

fn main() {
Logger::new()
.level(Level::Debug)
.init()
.unwrap();

// Standard log macros now go through sheen
log::info!("server started");
log::warn!("cache nearly full");
}
```

## Formatters

### Text (default)
Expand Down
13 changes: 13 additions & 0 deletions examples/log_adapter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use sheen::{Level, Logger};

fn main() {
// sheen as the log backend
Logger::new().level(Level::Trace).init().unwrap();

// These are log crate macros, not sheen macros
log::trace!("starting up");
log::debug!("loading configuration");
log::info!("server listening on port 3000");
log::warn!("cache is nearly full");
log::error!("failed to connect to database");
}
28 changes: 28 additions & 0 deletions src/level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,34 @@ impl Level {
}
}

// Converting log::Level to sheen::Level
#[cfg(feature = "log")]
impl From<log::Level> for Level {
fn from(level: log::Level) -> Self {
match level {
log::Level::Trace => Level::Trace,
log::Level::Debug => Level::Debug,
log::Level::Info => Level::Info,
log::Level::Warn => Level::Warn,
log::Level::Error => Level::Error,
}
}
}

// reverse
#[cfg(feature = "log")]
impl From<Level> for log::LevelFilter {
fn from(level: Level) -> Self {
match level {
Level::Trace => log::LevelFilter::Trace,
Level::Debug => log::LevelFilter::Debug,
Level::Info => log::LevelFilter::Info,
Level::Warn => log::LevelFilter::Warn,
Level::Error => log::LevelFilter::Error,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ mod level;
mod logger;
mod macros;

#[cfg(feature = "log")]
mod log_adapter;

pub use formatter::{Formatter, JsonFormatter, LogFmtFormatter, TextFormatter};
pub use global::{info, init, init_with};
pub use level::Level;
Expand Down
20 changes: 20 additions & 0 deletions src/log_adapter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::Logger;

impl log::Log for Logger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
self.enabled(metadata.level().into())
}
fn log(&self, record: &log::Record) {
if !self.enabled(record.level().into()) {
return;
}
let msg = format!("{}", record.args());
let target = record.target();
self.log(
record.level().into(),
&msg,
&[("target", &target as &dyn std::fmt::Debug)],
);
}
fn flush(&self) {}
}
10 changes: 10 additions & 0 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,13 @@ impl Default for Logger {
}
}
}

#[cfg(feature = "log")]
impl Logger {
pub fn init(self) -> Result<(), log::SetLoggerError> {
let max_level: log::LevelFilter = self.level.into();
log::set_boxed_logger(Box::new(self))?;
log::set_max_level(max_level);
Ok(())
}
}