fern/
syslog.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*!
Example usage of `fern` with the `syslog` crate.

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

```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`:

```no_run
# use syslog6 as syslog;
# fn setup_logging() -> Result<(), Box<dyn std::error::Error>> {
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()?;
# Ok(())
# }
# fn main() { setup_logging().ok(); }
```

---

## 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](https://github.com/Geal/rust-syslog/issues/39), 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.

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

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

```rust
# use syslog3 as syslog;
# fn setup_logging() -> Result<(), Box<dyn std::error::Error>> {
fern::Dispatch::new()
    .chain(syslog::unix(syslog::Facility::LOG_USER)?)
    .apply()?;
# Ok(())
# }
# fn main() { setup_logging().ok(); }
```

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:

```no_run
# use syslog6 as syslog;
# fn setup_logging() -> Result<(), Box<dyn std::error::Error>> {
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()?;
# Ok(())
# }
# fn main() { setup_logging().ok(); }
```

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.

```no_run
# use syslog6 as syslog;
# fn setup_logging() -> Result<(), Box<dyn std::error::Error>> {
# let formatter = syslog::Formatter3164 {
#     facility: syslog::Facility::LOG_USER,
#     hostname: None,
#     process: "hello-world".to_owned(),
#     pid: 0,
# };
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()?;
# Ok(())
# }
# fn main() { setup_logging().ok(); }
```

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:

```no_run
# use log::{debug, info, warn};
# fn main() {
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!");
# }
```
*/