Giter Site home page Giter Site logo

fern's Introduction

fern

crates.io version badge Build Status Average time to resolve an issue

Simple, efficient logging for Rust.


fern 0.4.4, 0.5.*, 0.6.* security warning - colored feature + global allocator

One of our downstream dependencies, atty, through colored, has an unsoundness issue: https://rustsec.org/advisories/RUSTSEC-2021-0145.html.

This shows up in one situation: if you're using colored (the crate, or our feature), and a custom global allocator.

I will be releasing fern 0.7.0, removing colored as a dependency. This may add another color crate, or may just document usage of alternatives (such as owo-colors + enable-ansi-support).

In the meantime, if you're using #[global_allocator], I highly recommend removing the fern/colored feature.

Or, for minimal code changes, you can also enable the colored/no-colors feature:

cargo add colored --features no-color

With the no-color feature, the vulnerable code will still be present, but unless you use any of the following APIs manually, it will never be called:

See #113 for further discussion.


Logging configuration is recursively branched, like a fern: formatting, filters, and output can be applied recursively to match increasingly specific kinds of logging. Fern provides a builder-based configuration backing for rust's standard log crate.

//! With fern, we can:

// Configure logger at runtime
fern::Dispatch::new()
    // Perform allocation-free log formatting
    .format(|out, message, record| {
        out.finish(format_args!(
            "[{} {} {}] {}",
            humantime::format_rfc3339(std::time::SystemTime::now()),
            record.level(),
            record.target(),
            message
        ))
    })
    // Add blanket level filter -
    .level(log::LevelFilter::Debug)
    // - and per-module overrides
    .level_for("hyper", log::LevelFilter::Info)
    // Output to stdout, files, and other Dispatch configurations
    .chain(std::io::stdout())
    .chain(fern::log_file("output.log")?)
    // Apply globally
    .apply()?;

// and log using log crate macros!
info!("hello, world!");

Examples of all features at the api docs. See fern in use with this example command line program.


Project Status

The fern project is primarily maintained by myself, @daboross on GitHub. It's a hobby project, but one I aim to keep at a high quality.

Contributing

As this is a hobby project, contributions are very welcome!

The easiest way for you to contribute right now is to use fern in your application, and see where it's lacking. The current library has a solid base, but it lacks features, and I may not anticipate your use cases.

If you have a use case fern does not cover, please file an issue. This is immensely useful to me, to anyone wanting to contribute to the project, and to you as well if the feature is implemented.

If you're interested in helping fix an existing issue, or an issue you just filed, help is appreciated.

See CONTRIBUTING for technical information on contributing.

fern's People

Contributors

alexanderkjall avatar autarch avatar daboross avatar dekellum avatar exphp avatar gareins avatar gingerdevilish avatar itkovian avatar jakunar avatar ondrowan avatar palladinium avatar roguelazer avatar sbercx avatar songtronix avatar sourcefrog avatar tanujitghosh avatar thijsc avatar tymcauley avatar vorner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fern's Issues

Support colored terminal output on Windows

Ideally, this would be a stdout-like color output stream which parsed ANSI color codes and transformed them into the correct output on both Windows and UNIX terminals.

Crates of note:

  • https://crates.io/crates/termcolor provides a platform-agnostic colored stdout writer. The downside is each color needs to be specified via a method, it can't parse ANSI color codes passed to it.
  • https://crates.io/crates/wincolor is the backend termcolor uses on windows (we might want to just depend on this if we don't need to do anything else on linux)

Ideas for implementation:

  • We can test the functionality in fern, but it would probably be good to separate out "stream which turns ANSI color codes into windows commands" into a separate crate.
  • If we find a simpler ANSI color code only crate, we might want to remove our dependency on https://crates.io/crates/colored. We don't use very much of its functionality right now, so we'd have a lighter footprint if we switched to something which only provided ANSI codes.

Coloring loglevels end up in log file as well

If I activate coloring of the log levels I end up with the color escape codes in my file as well. Is there any way to make fern log to stdout and to a file but only color stdout?

Log crate

I have been using this crate without

log = "*"

inside Cargo.toml. Well, it still worked up to a point, that where rustc complained that there was no log::LogLevelFilter inside log crate. If you could add this detail to crate documentation, it would be great.

I know, there is a dependancy on log 0.2.5, but somehow I had to manually add it into Cargo.toml.

Gareins

Recipes for CLI logging with fern

Fern is currently nice to configure, but might be a bit verbose for someone just wanting a CLI logger. It would be nice if we had some easy to use recipes for common use cases.

While this would be beneficial, I don't think adding additional duplicated functionality to fern itself would be a good idea. Instead, a crate fern-recipes could be created, containing a bunch of helper functions, each with two variations: returning std::io::Result<fern::Logger>, and returning Result<(), fern::InitError>.

If anyone has a better idea on how to include these recipes, or wants to start making some, feel free to chime in below.

Add feature for syslog 5

Should be fairly straightforward, we can do the same thing we did for the syslog3/4 distinction for adding support for syslog 5. Main work is in rewriting full examples to use syslog 5.

There were some things that syslog 3 could do, but syslog 4 couldn't. I can't remember off the top of my head what they were. If syslog 5 fixes these, and is at least as capable as both syslog 3 and 4, we can remove syslog 3/4 examples and leave only actual library code, replacing them entirely with syslog 5 examples.

Color codes in output files

[2019-09-29 22:37:40][�[32mINFO �[0m][test] Hello, world!
[2019-09-29 22:37:40][�[33mWARN �[0m][test] Hello, world!
[2019-09-29 22:37:40][�[31mERROR�[0m][test] Hello, world!

Is there a way to prevent fern from writing color codes into files?

Output to arbitrary Write object

Hello

I'm looking through logging options available that'd fullfill my use case. Part of it could be done with fern, but there's one small bit lacking. I'd like to plug an arbitrary Write object into it.

Would it make sense to add another From implementation, accepting Box<Write> in addition to all the specific ones? I think it would increase the flexibility.

How to filter different levels for different targets?

i use fern for logging things in my integration tests. Lets say I only use one blanket LevelFilter for all modules (though this is not the case). I'd love to be able to send everything LevelFilter::Info and above to my log file, then restrict it further to everything LevelFilter::Warn and above to send to STDOUT. Is there already a way to do this, and if not, could it be considered as an enhancement?

Any plans for syslog integration?

There are two crates syslog and sysly neither of them integrates either with log or fern. Any plans on this?

Should syslog logger be in fern? Should it be under feature flag?

log_file not allow internal logging

This example stalling after writing second "Kek" but works fine if "log_file" commented.

// log = "0.4.14"
// fern = "0.6.0"

use std::fmt;

fn setup_logger() -> Result<(), fern::InitError> {
    fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "[{}][{}] {}",
                record.target(),
                record.level(),
                message
            ))
        })
        .level(log::LevelFilter::Debug)
        .chain(std::io::stdout())
        .chain(fern::log_file("output.log")?)
        .apply()?;
    Ok(())
}

fn main() {
    setup_logger().unwrap();
    println!("run");
    log::error!("Error: {}", get_str());

    println!("exiting");
}
struct Error;
impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        log::debug!("Kek");
        write!(f, "wow")
    }
}

fn get_str() -> &'static str {
    log::warn!("get_str: {}", Error);
    "test"
}
     Running `target/debug/test_i18_stall`
run
[test_i18_stall][WARN] get_str: [test_i18_stall][DEBUG] Kek
wow
[test_i18_stall][DEBUG] Kek

gdb backtrace after interrupting

(gdb) bt
#0  0x00007ffff7f93610 in __lll_lock_wait () from /lib64/libpthread.so.0
#1  0x00007ffff7f8bf53 in pthread_mutex_lock () from /lib64/libpthread.so.0
#2  0x0000555555578dbd in std::sys::unix::mutex::Mutex::lock (self=0x5555555f3ed0)
    at /home/evgen/.rustup/toolchains/1.47.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/unix/mutex.rs:63
#3  0x0000555555563f8a in std::sys_common::mutex::Mutex::raw_lock (self=0x5555555f3ed0)
    at /home/evgen/.rustup/toolchains/1.47.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/mutex.rs:42
#4  0x0000555555571d26 in std::sync::mutex::Mutex<T>::lock (self=0x5555555f3f90)
    at /home/evgen/.rustup/toolchains/1.47.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sync/mutex.rs:269
#5  0x0000555555578048 in <fern::log_impl::File as log::Log>::log::{{closure}} (record=0x7fffffffc3b8)
    at /home/evgen/.cargo/registry/src/github.com-1ecc6299db9ec823/fern-0.6.0/src/log_impl.rs:549
#6  0x0000555555577eb1 in fern::log_impl::fallback_on_error (record=0x7fffffffc3b8, log_func=...)
    at /home/evgen/.cargo/registry/src/github.com-1ecc6299db9ec823/fern-0.6.0/src/log_impl.rs:733
#7  <fern::log_impl::File as log::Log>::log (self=0x5555555f3f90, record=0x7fffffffc3b8)
    at /home/evgen/.cargo/registry/src/github.com-1ecc6299db9ec823/fern-0.6.0/src/log_impl.rs:535
#8  0x0000555555575e44 in <fern::log_impl::Output as log::Log>::log (self=0x5555555f3f88, record=0x7fffffffc3b8)
    at /home/evgen/.cargo/registry/src/github.com-1ecc6299db9ec823/fern-0.6.0/src/log_impl.rs:326
#9  0x00005555555763a4 in fern::log_impl::Dispatch::finish_logging (self=0x5555555f1e30, record=0x7fffffffc3b8)
    at /home/evgen/.cargo/registry/src/github.com-1ecc6299db9ec823/fern-0.6.0/src/log_impl.rs:427
#10 0x00005555555767f1 in fern::log_impl::FormatCallback::finish (self=..., formatted_message=...)
    at /home/evgen/.cargo/registry/src/github.com-1ecc6299db9ec823/fern-0.6.0/src/log_impl.rs:487

The `log_enabled` is sometimes inaccurate.

Hello

I've managed to get the log_enabled out of sync from what is actually logged in the end (this is a small reproducer, but I've actually hit it in production where it gives me some trouble).

use log::{debug, info, log_enabled};

fn main() {
    let dummy = fern::Dispatch::new()
        .level(log::LevelFilter::Warn)
        .chain(std::io::stderr());

    let stdout = fern::Dispatch::new()
        .level(log::LevelFilter::Info)
        .level_for("abc", log::LevelFilter::Debug)
        .chain(std::io::stdout());

    fern::Dispatch::new()
        .chain(stdout)
        .chain(dummy)
        .apply()
        .unwrap();

    info!("Hello world");

    debug!("Should not show");

    dbg!(log_enabled!(log::Level::Debug));
}

The output is this:

Hello world
[src/main.rs:23] log_enabled!(log :: Level :: Debug) = true

So, it doesn't log the debug message, but says log is enabled for debug.

Is this on purpose (not chasing through the slave Dispatches because of performance), or just some kind of missed thing?

Fully Colored Line

Is there a way to color the full line based on its level? For instance, if the level is error, the color of the full line would be red.

Moving to reopen 1.0

Hello

I've released reopen 1.0 and intend to consider it stable (well, it didn't need any touching for 2 years, so I guess it is „complete“). And I wanted to send a pull request with update, but I'm a bit unsure about one thing.

It's turned on by the reopen-03 feature. Is it OK to remove that one and replace by a reopen-1 or do you want to support both in parallel?

(Question) How would I chain a time based log?

I want it to log into logs/mm-dd-yyyy.log, but if the program is online for more than a day this will become outdated, how would I make it automatically switch to the next day's file?

Docs need updated certificate

It looks like the cert for your website expired on the 23rd because every time I try to read the fern docs chromium shows the "Your connection is not private" message (NET::ERR_CERT_DATE_INVALID).

Bug with coloration in file logging

Hi,

I've set up logs coloration and output, and have this:

2020/01/22 22:08:21 �[92mINFO�[0m [lucid::server] Running Lucid server on 127.0.0.1:7021 | PID: 48400
2020/01/22 22:08:21 �[92mINFO�[0m [lucid::server] Lucid API Endpoint: https://127.0.0.1:7021/api/
2020/01/22 22:08:21 �[92mINFO�[0m [lucid::server] Use Ctrl+C to stop the server.

A bit boring ^^

Current implementation here: lucid-kv/lucid#49

Kind regards

log_reopen requires undocumented feature switch

In fern 0.6.0, the log_reopen function depends on the reopen-03 feature to be enabled, which it isn't by default. This isn't documented, and it results in a pretty confusing error message about the function not existing in a typical usage scenario.

Unresolved import `fern::colors`

I'm trying to use fern with one of the examples in the repo:

// ...
extern crate log;
extern crate fern;
// ...
use fern::colors::{Color, ColoredLevelConfig};
use log::{debug, error, info, trace, warn};

fn main() {
    setup_logger();
//...
}
fn setup_logger() {
    let colors_line = ColoredLevelConfig::new()
        .error(Color::Red)
        .warn(Color::Yellow)
        .info(Color::White)
        .debug(Color::White)
        .trace(Color::BrightBlack);

    let colors_level = colors_line.clone().info(Color::Green);
    fern::Dispatch::new()
        .format(move |out, message, record| {
            out.finish(format_args!(
                "{color_line}[{date}][{target}][{level}{color_line}] {message}\x1B[0m",
                color_line = format_args!(
                    "\x1B[{}m",
                    colors_line.get_color(&record.level()).to_fg_str()
                ),
                date = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                target = record.target(),
                level = colors_level.color(record.level()),
                message = message,
            ));
        })
        .level(log::LevelFilter::Warn)
        .level_for("pretty_colored", log::LevelFilter::Trace)
        .chain(std::io::stdout())
        .apply()
        .unwrap();

    debug!("finished setting up logging! yay!");
}

This is the output of cargo build:

   Compiling piko v0.1.0 (/home/lyubentodorov/Projects/piko)
error[E0432]: unresolved import `fern::colors`
  --> src/bin/main.rs:33:11
   |
33 | use fern::colors::{Color, ColoredLevelConfig};
   |           ^^^^^^ could not find `colors` in `fern`

warning: unused imports: `error`, `trace`, `warn`
  --> src/bin/main.rs:34:18
   |
34 | use log::{debug, error, info, trace, warn};
   |                  ^^^^^        ^^^^^  ^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0432`.
error: could not compile `piko`.

To learn more, run the command again with --verbose.

And these are my dependancies:

[dependencies]
rand = "0.7.3"
config = "0.10.1"
rayon = "1.3.1"
sha2 = "0.9.1"
byteorder = "1.3.4"
bytes = "0.5.6"
num = "0.3.0"
num-traits = "0.2.12"
num-derive = "0.3.1"
serde = { version = "1.0.115", features = ["derive"] }
serde_cbor = "0.11.1"
clokwerk = "0.3.3"
lazy_static = "1.4.0"
log = "0.4"
fern = "0.5"
chrono = "0.4.15"

I've tried with a couple of versions of log and fern, including the latest ones. I can't see what I'm doing wrong and I couldn't find similar issues anywhere.

JSON

I'm trying to implement JSON logging using fern, but I'm having issues with messages containing newlines.

See this example program:

fn main() {
    let mut dispatch = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{{ \"message\": \"{}\" }}",
                message
            ))
        })
        .chain(std::io::stdout())
        .apply().unwrap();
    log::info!("This is a single line and works fine");
    log::info!("This is mulitple lines\n and doesn't produce valid JSON");
}

And the output:

{ "message": "This is a single line and works fine" }
{ "message": "This is mulitple lines
 and doesn't produce valid JSON" }

Is there any good way of escaping the newline(s) in the message?

Fern and forks

Hi, I'm interested in using fern logging in forked subprocesses, however, I don't see a way to uninstall the parent process's global logger and install a child process logger for the subprocess. What is the recommendation here?

No support for log targets?

The log crate allows the use of targets, which is useful to add information about the origin of a log message, but it seems fern provides no facility for reading targets from DispatchConfig. Could this be added?

https://doc.rust-lang.org/log/log/index.html

A log request consists of a target, a level, and a body. A target is a string which defaults to the module path of the location of the log request, though that default may be overridden. Logger implementations typically use the target to filter requests based on some user configuration.

An example from this page:
info!(target: "yak_events", "Commencing yak shaving for {:?}", yak);

Format width is not obeyed when using ColoredLevelConfig

This is my current configuration for fern, file_out logs with the correct level_width of 8, but term_out completely ignores the width.

I have also tested to see if it follows alignment formatting marks, and it does not.

    let colors = ColoredLevelConfig::new()
        .trace(Color::Magenta)
        .debug(Color::Cyan)
        .info(Color::Green)
        .warn(Color::Yellow)
        .error(Color::Red);

    let term_out = fern::Dispatch::new()
        .format(move |out, message, record| {
            out.finish(format_args!(
                "{time}  {level:level_width$}{target:target_width$}\t> {msg}",
                time = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                level = colors.color(record.level()),
                target = record.target(),
                msg = message,
                level_width = 8,
                target_width = 60
            ))
        })
        .chain(std::io::stdout())
        .into_shared();

    let file_out = fern::Dispatch::new()
        .format(move |out, message, record| {
            out.finish(format_args!(
                "{time}  {level:level_width$}{target:target_width$}\t> {msg}",
                time = chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                level = record.level(),
                target = record.target(),
                msg = message,
                level_width = 8,
                target_width = 60
            ))
        })
        .chain(fern::log_file("output.log").expect("Unable to access log file"))
        .into_shared();

    fern::Dispatch::new()
        .level(log::LevelFilter::Info)
        .level_for("momiji", log::LevelFilter::Debug)
        .chain(term_out)
        .chain(file_out)
        .apply().expect("Failed to apply fern settings");

Add support for easy custom loggers with closures

If there's another kind of backend that we don't support, it should be easy to add a shim in any user crate. This is for things which aren't Log either, so they don't fall into the Box<Log> handler.

I think this would be best done via an Output::other method like:

fn other<F>(handler: F) -> Self
where
    F: FnMut(log::Record)

It would be usable like:

fern::Dispatch::new()
    .chain(fern::Output::other(|record| actual_log(record)))

On the implementation side, we could use the existing implementations for Box<Log>.

The Output::other would have a function-local struct Shim<F: FnMut(log::Record)>(F); implementing log::Log.

Then the method can just return (Box::new(Shim(handler)) as Box<Log>).into().

logging to a file does not work at all

I've set up my logger:

fn set_up_logging() {

    use fern::InitError;
    use std::error::Error;

    /// Sets up the global logger
    fn set_up_logging_internal() -> Result<(), InitError> {
        fern::Dispatch::new()
            .format(|out, message, record| {
                out.finish(format_args!(
                    "[{}][{}] {}",
                    record.level(),
                    record.target(),
                    message
                ))
            })
            .chain(std::io::stdout())
            .chain(fern::log_file("my_log.log")?) // <------- see here
            .apply()?;
        Ok(())
    }

    match set_up_logging_internal() {
        Ok(_) => { },
        Err(e) => match e {
            InitError::Io(e) => {
                println!("[WARN] Logging IO init error: \r\nkind: {:?}\r\n\r\ndescription:\r\n{}\r\n\r\ncause:\r\n{:?}\r\n",
                           e.kind(), e.description(), e.cause());
            },
            InitError::SetLoggerError(e) => {
                println!("[WARN] Logging initalization error: \r\ndescription:\r\n{}\r\n\r\ncause:\r\n{:?}\r\n",
                    e.description(), e.cause());
            }
        }
    }
}

Then I tried to use it:

fn main() {
    set_up_logging(); 
    info!("hello world");
}

The stdout gets printed correctly, but the file is just empty. The log file is created, but not actually written to, which kind of defeats the point of a logger. Is there anything I'm doing wrong?

How to set different log levels for modules

Currently I am using this snippet to setup fern:

fn setup_logger() {
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
            let t = time::now();
            let ms = t.tm_nsec/1000_000;
            let path = _location.__module_path;
            let line = _location.__line;

            format!("{}.{:3} [{}] {} {}: {}", t.strftime("%Y-%m-%dT%H:%M:%S").unwrap(), ms, level, path, line, msg)
        }),
        output: vec![fern::OutputConfig::stderr()],
        level: log::LogLevelFilter::Trace,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }
}

It sets up logging globally, however is it possible to setup different loglevels for different threads.

For example I would like that module mqtt::client would log only error messages. Is there possibility to do that?

Release documentation patch

We should release a patch with:

  • a fix for #55 (#56)
  • a fix for #54
  • some docs to clarify #52
  • some docs to clarify #50

Opening an issue for this since I'm not going to address it immediately, but it will be done. If you're from the far future, and I've not yet gotten to this, feel free to reply & send a ping.

Possibility of hooking into env_logger or adding env_logger-compatible configuration?

It'd be nice to be able to use fern's manual configuration and at the same time still get an additional RUST_LOG interface with only an additional flag.

As with #60, I'm not sure if this fits the crate. I think if we reused or reimplemented only the parsing, though, we might be able to combine configurations from inside the program and from the env variable, to allow them to benefit eachother rather than replace eachother? And if we implement it as a feature flag, then it shouldn't be too much additional overhead.

I think most of that logic applies to #60 too, so implementing both might be a good idea. We could even try to accept log4rs-compatible configuration.


On the other hand, fern's configuration is infinitely recursive, and it wouldn't be entirely clear where to stick / allow the target filters. Maybe it'd have to be a method on dispatch, "allow_from_env"?

How does this scale to the file configuration, then? Does it? Not sure.

Explore what key/value support should look like in fern

As of rust-lang/log#324, there's unstable support for key/value pairs in logging in log. For more information, see the tracking issue.

We probably want some amount of builtin support for key/value pairs in fern. It's unclear, though, exactly what form this support should take.

Some initial ideas:

  • filtering based on key values or keys being present
  • ability to add, remove and change keys while formatting
  • ability to output log messages, with key/value pairs & message, as JSON or others
  • some default way to incorporate kv pairs into formatting (might be a recipe?)

A more invasive setup could be:

  • add a new KeyValueDispatch dispatch type
    • can be created by specifying a function from (arguments, record) to key/value pairs
      • pushes responsibility onto user to decide what key "message" and "log level" end up as
      • we'd provide a sane default which maps all the record's fields to sane names, maybe namespaced
  • add the combinators from Dispatch to KeyValueDispatch, of course each giving/accepting a KeyValueDispatch instead
  • replace format with map - a general kv map with the same principles
  • replace output's single argument with multiple: one specifying a format (like newline-separated JSON), the other specifying where to write it

I'm not committed to any of these, this is just initial brainstorming.

We'll probably want to look at what one can do with key/value pairs in logging configuration in slog too, as they've explored this problem space a lot more than we have.

ColoredLevelConfig::new() fails to compile on Windows

Compiling on Windows with Rust stable v1.42.0 and
fern = { version = "^0.6", features = ["colored"] }

gives:

error[E0425]: cannot find function `set_virtual_terminal` in module `colored::control`
   --> C:\Users\braxton\.cargo\registry\src\github.com-1ecc6299db9ec823\fern-0.6.0\src\colors.rs:161:39
    |
161 |             let _ = colored::control::set_virtual_terminal(true);
    |                                       ^^^^^^^^^^^^^^^^^^^^ not found in `colored::control

That section of your code is:

    #[inline]
    pub fn new() -> Self {
        #[cfg(windows)]
        {
            let _ = colored::control::set_virtual_terminal(true);
        }
        Self::default()
    }

And after looking over the colored crate, there's indeed nothing even resembling that in that module.
Perhaps this should be colored::control::set_override(true);?

Add line numbers in logs?

Having line numbers like other languages would be nice to locate error when debugging, but I haven't seen any mention about line numbers.

Isn't it supported? (seems no "line" in the codebase)

Mismatched type returned from log_file

I'm using fern = "0.5" in Cargo.toml

When I use the sample code in CLion IDE, the line .chain(fern::log_file("output.log")?) displays warning mismatched types expected Result<File, Error>, found File

When I go modify the Fern library file fern-0.5.5/src/lib.rs and change the signature from pub fn log_file<P: AsRef<Path>>(path: P) -> io::Result<File> { to pub fn log_file<P: AsRef<Path>>(path: P) -> File { then the warning disappears, and the implementation still outputs to the log file and terminal successfully.

Recipe for colored logging

It would be nice to have some examples for using fern with colored logging.

Right now this will probably be tricky, especially because there is no LogLevel->Color mapping created.

For implementing colors, ansi_term seems like a good crate to use. We could either build an example with this, or add it as an optional dependency to fern, and create helper functions.

Asynchronous log sinks with fern?

I'm planning to use fern in the asynchronous app and non-blocking logging is vital for us.

How can I setup fern to implement async logging? Can it write logs in a separate thread or at least use mpsc::channel as an output?

Link to docs is broken

The link to the documentation is broken. Would be simple enough to create a gh-pages branch and just use rustdoc?

Capture logs inside tests?

Hi,

It would be great if tests could be written to the tests's stdout, and then (by default) shown only if the test fails.

It looks like .chain(std::io::stdout()) sends them to the process's real stdout, bypassing the test framework's hooks. I see there's a lot of history on this in rust-lang/rust#42474 and perhaps it's not possible for Fern to fix? But it seems like if println! is captured, at least Fern could simply do println! for everything.

Or perhaps this is possible already and I'm just missing it, and if so perhaps it could be clearer in the docs?

Proposal: panic on `error` or `warn` on some condition

It'd be very nice to panic! instead of trying writing something when we are running tests. Could we have an option which specified what to do in error! or warn! handlers? Panicking in the tests very useful because we may see some problems we may have. Personally I provide two kind of critical functions - one uses error! and another one uses panic! for showing me why my test fails.

Add an field to FormatCallback indicate support of color

for example we could use it like this:

fern::Dispatch::new()
    // ...
    .format(move |out, message, record| {
        out.finish(format_args!(
            "[{}] {}",
            // if out.color, we render it with ANSI color (e.g. io::stdout())
            // otherwise render it as plain text (e.g. fern::log_file)
            if out.color { colors.color(record.level()) } else { record.level() },
            message
        ))
    })

Add line numbers in log?

Having line numbers like other languages would be nice to locate error when debugging, but I haven't seen any mention about line numbers.

Isn't it supported? (seems no "line" in the codebase)

Chaining vec of Dispatch

Hello!
How can I chain vec of fern::Dispatch ?

    let mut logger_base = Dispatch::new();
    logger_base.level(log_level);

    for logger in loggers.iter(){
        logger_base.chain(logger)
    }

    logger_base.apply()?;

I am struggling with this for a whole day

Log file which self-truncates after a certain size

I think it would be sane to add an option for a simple log file which removes old records once it reaches 16 megabytes, or a similar size. This would be useful for sane command line applications which might want to output much more debug logging, and now wouldn't have to worry about cleaning it up.

This would need to be implemented efficiently though, so more knowledge on ways to do this in Linux and Windows is needed.

newlines in output files?

This may not just be for this library, but I used this on windows and it created an output file with unix end-of-line characters. I'm used to python doing magic newline conversions in a windows environment. I couldn't seem to find where the newline character was appended to the message but perhaps using something akin to the Python os.linesep would be better?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.