fern

Module syslog

source
Expand description

Example usage of fern with the syslog crate.

Be sure to depend on syslog and the syslog feature in Cargo.toml:

[dependencies]
fern = { version = "0.7", features = ["syslog-6"] }]
syslog = "6"

To use syslog, simply create the log you want, and pass it into Dispatch::chain:

let formatter = syslog::Formatter3164 {
    facility: syslog::Facility::LOG_USER,
    hostname: None,
    process: "hello-world".to_owned(),
    pid: 0,
};

fern::Dispatch::new()
    .chain(syslog::unix(formatter)?)
    .apply()?;

§Alternate syslog versions

If you’re using syslog=4.0.0 exactly, one line “ok” will be printed to stdout on log configuration. This is a bug in syslog, and there is nothing we can change in fern to fix that.

One way to avoid this is to use a different version of syslog, fern also supports. To pin syslog3, use the syslog-3 feature and depend on syslog = "3" instead.

[dependencies]
fern = { version = "0.7", features = ["syslog-3"] }]
syslog = "3"

The setup is very similar, except with less configuration to start the syslog logger:

fern::Dispatch::new()
    .chain(syslog::unix(syslog::Facility::LOG_USER)?)
    .apply()?;

The rest of this document applies to all syslog versions, but the examples will be using syslog 6 as it is the latest version.


One thing with syslog is that you don’t generally want to apply any log formatting. The system logger will handle that for you.

However, you probably will want to format messages you also send to stdout! Fortunately, selective configuration is easy with fern:

let syslog_formatter = syslog::Formatter3164 {
    facility: syslog::Facility::LOG_USER,
    hostname: None,
    process: "hello-world".to_owned(),
    pid: 0,
};

// top level config
fern::Dispatch::new()
    .chain(
        // console config
        fern::Dispatch::new()
            .level(log::LevelFilter::Debug)
            .format(move |out, message, record| {
                out.finish(format_args!(
                    "[{}] {}",
                    record.level(),
                    message,
                ))
            })
            .chain(std::io::stdout())
    )
    .chain(
        // syslog config
        fern::Dispatch::new()
            .level(log::LevelFilter::Info)
            .chain(syslog::unix(syslog_formatter)?)
    )
    .apply()?;

With this, all info and above messages will be sent to the syslog with no formatting, and the messages sent to the console will still look nice as usual.


One last pattern you might want to know: creating a log target which must be explicitly mentioned in order to work.

fern::Dispatch::new()
    // by default only accept warning messages from libraries so we don't spam
    .level(log::LevelFilter::Warn)
    // but accept Info and Debug if we explicitly mention syslog
    .level_for("explicit-syslog", log::LevelFilter::Debug)
    .chain(syslog::unix(formatter)?)
    .apply()?;

With this configuration, only warning messages will get through by default. If we do want to send info or debug messages, we can do so explicitly:

debug!("this won't get through");
// especially useful if this is from library you depend on.
info!("neither will this");
warn!("this will!");

info!(target: "explicit-syslog", "this will also show up!");