slog-rs / slog

Structured, contextual, extensible, composable logging for Rust
https://slog.rs/
Apache License 2.0
1.58k stars 95 forks source link

Trying to build a JSON logger without async #285

Closed dcormier closed 3 years ago

dcormier commented 3 years ago

I'm trying to build a slog_json logger without using slog_async. I'm trying to write the JSON logs to a buffer and verify they contain certain output later, so I need logging to be a blocking operation so that the buffer actually has the content when .log returns.

This code:

let log = Logger::root(slog_json::Json::new(std::io::stdout()).build().fuse(), o!());

Results in this:

error[E0277]: `RefCell<Stdout>` cannot be shared between threads safely
    --> logging/src/lib.rs:266:19
     |
266  |         let log = Logger::root(slog_json::Json::new(std::io::stdout()).build().fuse(), o!());
     |                   ^^^^^^^^^^^^ `RefCell<Stdout>` cannot be shared between threads safely
     | 
    ::: /Users/[snip]/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-2.7.0/src/lib.rs:1149:49
     |
1149 |         D: 'static + SendSyncRefUnwindSafeDrain<Err = Never, Ok = ()>,
     |                                                 ----------- required by this bound in `Logger::<D>::root`
     |
     = help: within `slog::Fuse<slog_json::Json<Stdout>>`, the trait `Sync` is not implemented for `RefCell<Stdout>`
     = note: required because it appears within the type `slog_json::Json<Stdout>`
     = note: required because it appears within the type `slog::Fuse<slog_json::Json<Stdout>>`
     = note: required because of the requirements on the impl of `SendSyncUnwindSafeDrain` for `slog::Fuse<slog_json::Json<Stdout>>`

error[E0277]: the type `UnsafeCell<Stdout>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    --> logging/src/lib.rs:266:19
     |
266  |         let log = Logger::root(slog_json::Json::new(std::io::stdout()).build().fuse(), o!());
     |                   ^^^^^^^^^^^^ `UnsafeCell<Stdout>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
     | 
    ::: /Users/[snip]/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-2.7.0/src/lib.rs:1150:38
     |
1150 |         T: SendSyncRefUnwindSafeKV + 'static,
     |                                      ------- required by this bound in `Logger::<D>::root`
     |
     = help: within `slog::Fuse<slog_json::Json<Stdout>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<Stdout>`
     = note: required because it appears within the type `RefCell<Stdout>`
     = note: required because it appears within the type `slog_json::Json<Stdout>`
     = note: required because it appears within the type `slog::Fuse<slog_json::Json<Stdout>>`
     = note: required because of the requirements on the impl of `SendSyncRefUnwindSafeDrain` for `slog::Fuse<slog_json::Json<Stdout>>`

error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    --> logging/src/lib.rs:266:19
     |
266  |         let log = Logger::root(slog_json::Json::new(std::io::stdout()).build().fuse(), o!());
     |                   ^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
     | 
    ::: /Users/[snip]/.cargo/registry/src/github.com-1ecc6299db9ec823/slog-2.7.0/src/lib.rs:1150:38
     |
1150 |         T: SendSyncRefUnwindSafeKV + 'static,
     |                                      ------- required by this bound in `Logger::<D>::root`
     |
     = help: within `slog::Fuse<slog_json::Json<Stdout>>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`
     = note: required because it appears within the type `Cell<isize>`
     = note: required because it appears within the type `RefCell<Stdout>`
     = note: required because it appears within the type `slog_json::Json<Stdout>`
     = note: required because it appears within the type `slog::Fuse<slog_json::Json<Stdout>>`
     = note: required because of the requirements on the impl of `SendSyncRefUnwindSafeDrain` for `slog::Fuse<slog_json::Json<Stdout>>`

Surely slog_async isn't a requirement for writing logs, is it?

dcormier commented 3 years ago

The solution for this is to wrap the Drain in a Mutex.

Before:

let log = Logger::root(
    slog_json::Json::new(std::io::stdout()).build().fuse(),
    o!(),
);

After:

let log = Logger::root(
    Mutex::new(
        slog_json::Json::new(std::io::stdout()).build().fuse(),
    ).fuse(),
    o!(),
);

Newlines for clarity.

at15 commented 3 years ago

Found the issue while google for term logger... You can find different sync methods in slog-term's doc https://docs.rs/slog-term/2.8.0/slog_term/#synchronization-via-plainsyncdecorator and some formatter are Sync FullFormat while some are not CompactFormat