Crate fern [] [src]

Fern is a runtime-configurable rust logging library.

Current features:

  • Multiple loggers. You can create as many loggers as you need, and configure them separately.
  • Configurable output format via closures.
  • Multiple outputs per logger - output to any combination of:
    • log files
    • stdout or stderr
    • your own custom implementation
  • Each output can have a Level configured, so you can output all log messages to a log file, and only have warnings and above show up in the console.
  • You can also define your own custom logging endpoints - have messages end up where you need them.
  • Acts as a backend to the log crate - use trace!() through error!() to log to the global fern logger.
    • Note that fern can also have loggers separate from the global system. You can always set your main logger as the global logger, then use other fern loggers manually.

Although mostly stabilized, fern is still in development. The library is subject to change in non-backwards-compatible ways before the API is completely stabilized.

This library can only be used while complying to the license terms in the LICENSE file.

Upgrade note for fern 0.2.*

As of fern 0.2.0, fern depends on the log crate to provide the frontend logging macros and logging levels - you will need to depend on and use both the fern and log crates.

Adding fern as a dependency

In order to use fern, the first thing you'll need to add both the fern crate and the log crate to the dependencies in your project's Cargo.toml file:

# ...

[dependencies]
# ...
log = "0.2.*"
fern = "0.2.*"

# ...

After this, you'll need to declare the log and fern at the top of your main.rs or lib.rs file:

#[macro_use]
extern crate log;
extern crate fern;

Examples

Usually, the first thing you want to do is create a logger. In fern, you can do this by first creating a LoggerConfig struct, and then calling .into_logger() to turn it into a logger.

Here's a logger that simply logs all messages to stdout, and an output.log file, formatting each message with the current date, time, and logging level.

extern crate fern;
extern crate log;
extern crate time;

let logger_config = fern::DispatchConfig {
    format: Box::new(|msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
        // This is a fairly simple format, though it's possible to do more complicated ones.
        // This closure can contain any code, as long as it produces a String message.
        format!("[{}][{}] {}", time::now().strftime("%Y-%m-%d][%H:%M:%S").unwrap(), level, msg)
    }),
    output: vec![fern::OutputConfig::stdout(), fern::OutputConfig::file("output.log")],
    level: log::LogLevelFilter::Trace,
};

In the above example, here's what each part does.

format: is a closure which all messages will be run through. In this example, use a format!() macro to format the messages using the logging level.

Side note: time::now().strftime("%Y-%m-%d][%H:%M:%S") is a usage of the time library to format the current date/time into a readable string. This particular format will produce a string akin to 2015-01-20][12:55:04

With this formatting, the final output of the logger will look something like:

[2015-01-20][12:55:04][INFO] A message logged at the Info logging level.

output: is a Vec<> of other configurations to send the messages to. In this example, we send messages to stdout (the console), and the file "output.log".

level: is a log::LogLevelFilter which describes the minimum level that should be allowed to pass through this logger. Setting this to LogLevelFilter::Trace allows all messages to be logged, as Trace is the lowest logging level.

After creating your logging config, you can pass it to init_global_logger to set it as the logger used with logging macros in the log crate. This function can only be called once, as the log crate may only be set up once.

Note that this function also accepts a LogLevelFilter. This is so that you can set a global minimum log level separate from the logger configuration. If you don't have any reason for anything else, just set this to log::LogLevelFilter::Trace.

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

This uses the if let Err(e) = syntax to catch any errors that happen when initializing the logger.

Eventually, this section will contain a few more examples as well. For now though, the above tutorial paired with the fern docs should be enough to get you started on configuring a logger for your project.

Logging

With the log crate, outputting messages is fairly simple. As long as you are using the log crate with #[macro_use], and you have initialized the global logger as shown above, you can use the log macros to log messages.

// You need to have #[macro_use] to use log macros
#[macro_use]
extern crate log;
extern crate fern;

fern::init_global_logger(...);

trace!("Trace message");
debug!("Debug message");
info!("Info message");
warn!("Warning message");
error!("Error message");

Structs

DispatchConfig

This is the base logger configuration in fern.

NullLogger

A logger implementation which does nothing with logged messages.

OutputConfig

This config struct contains various output options to send messages to.

Enums

InitError

Error that may occur within init_global_logger()

LogError

Error that may occur within logging

Traits

IntoLog

Trait which represents any logger configuration which can be built into a fern::Logger or log::Log.

Logger

Basic fern logger trait. Something you can send messages to. We have a separate trait from log::Log, because we want errors to propagate upwards and only print in the outermost logger.

Functions

init_global_logger

Initializes the global logger of the log crate with the specified log configuration. This will return an InitError(log::SetLoggerError) if the global logger has already been initialized.