18 releases

0.4.4 Aug 6, 2021
0.4.3 Jan 31, 2021
0.4.1 Oct 20, 2020
0.4.0 Jul 20, 2020
0.1.3 Nov 10, 2018

#88 in Debugging

Download history 2/week @ 2021-06-25 4/week @ 2021-07-02 4/week @ 2021-07-09 23/week @ 2021-07-16 3/week @ 2021-07-23 38/week @ 2021-07-30 46/week @ 2021-08-06 28/week @ 2021-08-13 4/week @ 2021-08-20 3/week @ 2021-08-27 4/week @ 2021-09-10 2/week @ 2021-09-17 1/week @ 2021-09-24 22/week @ 2021-10-01 22/week @ 2021-10-08

56 downloads per month
Used in spirit

Apache-2.0 OR MIT



Travis Build Status

Helpers and configuration fragments to integrate logging into the spirit configuration framework.

See the docs and the examples.


Licensed under either of

at your option.


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.


A [spirit] fragments and helpers to configure and control logging.

The [Fragment]s here allow to configure relatively complex logging (multiple loggers, different formats, different destinations), both from command line and the configuration. It allows runtime reloading of them.

Internally it is based on the [fern] crate and just adds the configuration and runtime reloading (through log-reroute).

It assumes the application doesn't set the global logger itself. It also sets the panic hook through the log_panics crate. The with-backtrace cargo feature is propagated through.


  • background: Includes the ability to log asynchronously ‒ the writing to log files happens in a background thread and allows the rest of the application to not block on IO.
  • cfg-help: Support for configuration options help at runtime. On by default.
  • with-backtrace: The log_panics logs with backtraces. On by default.
  • syslog: Adds the support for logging into syslog.


When using the automatic management with a pipeline, this is how a startup happens:

  • As soon as the pipeline is registered, a logging on the WARN level is sent to stderr.
  • After command line arguments are parsed the stderr logging is updated to reflect that (or left on the WARN level if nothing is set by the user).
  • After configuration is loaded from the files, full logging is configured according to that.

Integration with other loggers

If you need something specific (for example sentry), you can plug in additional loggers through the pipeline ‒ the [Dispatch] allows adding arbitrary loggers. The [Pipeline::map][spirit::fragment::pipeline::Pipeline::map] is a good place to do it.

Performance warning

This allows the user to create arbitrary number of loggers. Furthermore, the logging is synchronous by default and not buffered. When writing a lot of logs or sending them over the network, this could become a bottleneck.

Background logging

The background feature flag adds the ability to do the actual logging in a background thread. This allows not blocking the actual application by IO or other expensive operations.

On the other hand, if the application crashes, some logs may be lost (or, depending on setup, when the logging thread doesn't keep up). Also, you need to flush the logger on shutdown, by using the [FlushGuard].

It is done through the [Background] transformation.

Planned features

These pieces are planned some time in future, but haven't happened yet (pull requests are welcome).

  • Reconnecting to the remote server if a TCP connection is lost.
  • Log file rotation.
  • Colors on stdout/stderr.

Usage without Pipelines

It is possible to use without the [Pipeline][spirit::Pipeline], manually. However, certain care needs to be taken to initialize everything that needs to be initialized.

It is either possible to just get the [Dispatch] object and call [apply][Dispatch::apply], that however is a single-shot initialization and the logger can't be replaced.

The helper functions [init] and [install] can be used to gain the ability to replace [Dispatch] loggers multiple times.


Manual single use installation

use spirit::AnyError;
use spirit::prelude::*;
use spirit_log::Cfg;

# fn main() -> Result<(), AnyError> {
// Well, you'd get it somewhere from configuration, but…
let cfg = Cfg::default();
let logger = cfg.create("logger")?;
# Ok(()) }

Manual multiple-use installation

use spirit::AnyError;
use spirit::prelude::*;
use spirit_log::Cfg;

# fn main() -> Result<(), AnyError> {
// This part can be done multiple times.
let cfg = Cfg::default();
let logger = cfg.create("logger")?;
# Ok(()) }

Automatic usage with a Pipeline, reloading and command line options

use log::info;
use serde::Deserialize;
use spirit::{Pipeline, Spirit};
use spirit::prelude::*;
use spirit_log::{Cfg as LogCfg, CfgAndOpts as LogBoth, Opts as LogOpts};
use structopt::StructOpt;

#[derive(Clone, Debug, StructOpt)]
struct Opts {
    logging: LogOpts,

impl Opts {
    fn logging(&self) -> LogOpts {

#[derive(Clone, Debug, Default, Deserialize)]
struct Cfg {
    #[serde(default, skip_serializing_if = "LogCfg::is_empty")]
    logging: LogCfg,

impl Cfg {
    fn logging(&self) -> LogCfg {

fn main() {
    Spirit::<Opts, Cfg>::new()
            Pipeline::new("logging").extract(|opts: &Opts, cfg: &Cfg| LogBoth {
                cfg: cfg.logging(),
                opts: opts.logging(),
        .run(|_spirit| {
            info!("Hello world");

The configuration could look something like this:

level = "DEBUG"
type = "file"
filename = "/tmp/example.log"
clock = "UTC"


~127K SLoC