logsley 0.1.1

Opinionated logging library
Documentation
# logsley
This is an opinionated Rust logging library.

## Features
- Configure the logger with one function call
- Thread and task scoped variables
- 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:<br/>
  ![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.

fn main() {
    let _global_logger_guard =
        logsley::configure("info").unwrap();
    logsley::thread_scope("main", || {
        // Log named values:
        logsley::error!("logsley error {}", 1; "x" => 2);
        // {"time_ns":1604899904064111000,
        // "time":"2020-11-08T21:31:44.064-08:00",
        // "module":"opinion","level":"ERROR",
        // "message":"logsley error 1",
        // "thread":"main","x":2}
        logsley::warn!("logsley warn {}", 1; "x" => 2);
        logsley::info!("logsley info {}", 1; "x" => 2);
        logsley::debug!("logsley debug {}", 1; "x" => 2);
        logsley::trace!("logsley 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!(
                    "logsley in thread {}", 1; "x" => 2);
                // {"time_ns":1604899904065111000,
                // "time":"2020-11-08T21:31:44.065-08:00",
                // "module":"opinion","level":"INFO",
                // "message":"logsley in thread 1",
                // "thread":"thread1","x":2}
            })
        })
        .join()
        .unwrap();

        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::<impl core::ops::function::FnOnce<A> 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.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