# logsley This is an opinionated Rust logging library. ## Features - Configure the logger with one function call - Thread scoped variables - Task scoped variables, with the `async` feature enabled - See logging output from tests - Works with libraries that use [`log`](https://crates.io/crates/log), [`slog`](https://crates.io/crates/slog), [`slog-scope`](https://crates.io/crates/slog-scope), and [`slog-scope-futures`](https://crates.io/crates/slog-scope-futures). - Logs JSON by default. Set `DEV_LOG_FORMAT=full` env var to get pretty output in your terminal. - Adjust logging verbosity of modules with simple string parameter, and override it with the `RUST_LOG env var.` Example: `RUST_LOG=some::spammy::module=warn,my::buggy::module=trace`. See [`slog-envlogger`](https://docs.rs/slog-envlogger/2.2.0/slog_envlogger/) for details. - Approved by Sir Robin of Logsley:
![Cary Elwes as Robin Hood in the film Robin Hood Men in Tights (1993)](robinhood.jpg) ## Limitations - Uses macros ## Examples ```rust // You should do logging like this. let _global_logger_guard = logsley::configure("info").unwrap(); logsley::thread_scope("main", || { // Log named values: logsley::error!("err {}", 1; "x" => 2); // {"time_ns":1604899904064111000, // "time":"2020-11-08T21:31:44.064-08:00", // "module":"opinion", // "level":"ERROR", // "message":"err 1", // "thread":"main", // "x":2} logsley::warn!("warn {}", 1; "x" => 2); logsley::info!("info {}", 1; "x" => 2); logsley::debug!("debug {}", 1; "x" => 2); logsley::trace!("trace {}", 1; "x" => 2); // Log simple messages: log::info!("log {}", 1); // {"time_ns":1604899904065070000, // "time":"2020-11-08T21:31:44.065-08:00", // "module":"opinion", // "level":"INFO", // "message":"log 1", // "thread":"main"} std::thread::spawn(|| { logsley::thread_scope("thread1", || { logsley::info!("in thread {}", 1; "x" => 2); })}) .join() .unwrap(); // {"time_ns":1604899904065111000, // "time":"2020-11-08T21:31:44.065-08:00", // "module":"opinion", // "level":"INFO", // "message":"in thread 1", // "thread":"thread1", // "x":2} async_std::task::block_on( logsley::task_scope("task1", async move { logsley::info!( "logsley in task {}", 1; "x" => 2); })); // {"time_ns":1604899904065241000, // "time":"2020-11-08T21:31:44.065-08:00", // "module":"opinion", // "level":"INFO", // "message":"logsley in task 1", // "task":"task1", // "thread":"main", // "x":2} panic!("uhoh"); // {"time_ns":1604899904955593000, // "time":"2020-11-08T21:31:44.955-08:00", // "module":"log_panics", // "level":"ERROR", // "message":"thread 'main' panicked at 'uhoh': examples/opinion.rs:30\n // 0: backtrace::backtrace::libunwind::trace\n // at /.../backtrace-0.3.54/src/backtrace/libunwind.rs:90:5\n // backtrace::backtrace::trace_unsynchronized\n // at /.../backtrace-0.3.54/src/backtrace/mod.rs:66:5\n // 1: backtrace::backtrace::trace\n // at /.../backtrace-0.3.54/src/backtrace/mod.rs:53:14\n // 2: backtrace::capture::Backtrace::create\n // at /.../backtrace-0.3.54/src/capture.rs:176:9\n // 3: backtrace::capture::Backtrace::new\n // at /.../backtrace-0.3.54/src/capture.rs:140:22\n // 4: log_panics::init::{{closure}}\n // at /.../log-panics-2.0.0/src/lib.rs:52:25\n // 5: std::panicking::rust_panic_with_hook\n // at /.../library/std/src/panicking.rs:581:17\n // 6: std::panicking::begin_panic::{{closure}}\n // at /.../library/std/src/panicking.rs:506:9\n // 7: std::sys_common::backtrace::__rust_end_short_backtrace\n // at /.../library/std/src/sys_common/backtrace.rs:153:18\n // 8: std::panicking::begin_panic\n // at /.../library/std/src/panicking.rs:505:12\n // 9: opinion::main::{{closure}}\n // at examples/opinion.rs:30:9\n // 10: slog_scope::scope\n // at /.../slog-scope-4.3.0/lib.rs:248:5\n // 11: logsley::thread_scope\n // at src/lib.rs:179:5\n // 12: opinion::main\n // at examples/opinion.rs:5:5\n // 13: core::ops::function::FnOnce::call_once\n // at /.../library/core/src/ops/function.rs:227:5\n // 14: std::sys_common::backtrace::__rust_begin_short_backtrace\n // at /.../library/std/src/sys_common/backtrace.rs:137:18\n // 15: std::rt::lang_start::{{closure}}\n // at /.../library/std/src/rt.rs:66:18\n // 16: core::ops::function::impls:: for &F>::call_once\n // at /.../library/core/src/ops/function.rs:259:13\n // std::panicking::try::do_call\n // at /.../library/std/src/panicking.rs:381:40\n // std::panicking::try\n // at /.../library/std/src/panicking.rs:345:19\n // std::panic::catch_unwind\n // at /.../library/std/src/panic.rs:382:14\n // std::rt::lang_start_internal\n // at /.../library/std/src/rt.rs:51:25\n // 17: std::rt::lang_start\n // at /.../library/std/src/rt.rs:65:5\n // 18: _main\n", // "thread":"main"} }); } ``` For a runnable example, see [examples/opinion.rs](examples/opinion.rs). Set the default log level to `info`. The program will emit log messages with level `info` and higher. ```rust let _global_logger_guard = logsley::configure("info"); log::error!("emitted"); log::warn!("emitted"); log::info!("emitted"); log::debug!("not emitted"); log::trace!("not emitted"); ``` Set the default log level to `info` and set the level for `chatty::module1` to `warn`. ```rust let _global_logger_guard = logsley::configure("info,chatty::module1=warn"); ``` Use the environment variable to override default log level. `module1` still gets its special log level. ```rust std::env::set_var("RUST_LOG", "debug"); let _global_logger_guard = logsley::configure("info,module1=warn"); ``` Use the environment variable to set `module1` to `debug`. ```rust std::env::set_var("RUST_LOG", "module1=debug"); let _global_logger_guard = logsley::configure("info"); ``` ## Documentation https://docs.rs/logsley ## Alternatives - [log](https://crates.io/crates/log) - [log-panics](https://crates.io/crates/log-panics) - [slog](https://crates.io/crates/slog) - [slog-async](https://crates.io/crates/slog-async) - [slog-envlogger](https://crates.io/crates/slog-envlogger) - [slog-json](https://crates.io/crates/slog-json) - [slog-scope](https://crates.io/crates/slog-scope) - [slog-scope-futures](https://crates.io/crates/slog-scope-futures) - [slog-stdlog](https://crates.io/crates/slog-stdlog) - [slog-term](https://crates.io/crates/slog-term) ## Release Process 1. Edit `Cargo.toml` and bump version number. 1. Run `./release.sh` ## Changelog - v0.1.8 - Add `async` feature - v0.1.7 - Bugfix. - v0.1.6 - Add missing `slog` reexport. - v0.1.5 - Rename `OutputFormat::JSON` to `Json` to satisfy nightly clippy. - v0.1.4 - Update docs. - v0.1.3 - Fix missing slog_scope::logger error - v0.1.2 - Fix panic in configure_for_test - v0.1.1 - Make example code fit in crates.io's 60-column code views. - v0.1.0 - First published version ## TODO - DONE - Try to make this crate comply with the [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/). - DONE - Include Readme.md info in the crate's docs. - DONE - Make the repo public - DONE - Set up continuous integration tests and banner. - https://gitlab.com/mattdark/firebase-example/blob/master/.gitlab-ci.yml - https://medium.com/astraol/optimizing-ci-cd-pipeline-for-rust-projects-gitlab-docker-98df64ae3bc4 - https://hub.docker.com/_/rust - DONE - Add some documentation tests - https://doc.rust-lang.org/rustdoc/documentation-tests.html - https://doc.rust-lang.org/stable/rust-by-example/testing/doc_testing.html - DONE - Publish to creates.io - DONE - Read through https://crate-ci.github.io/index.html - DONE - Add and update a changelog - Update it manually - https://crate-ci.github.io/release/changelog.html - Get a code review from an experienced rustacean - Add features: threads, futures, term License: Apache-2.0