Skip to content

Commit 217e857

Browse files
author
Corentin Henry
committed
tracing-journald: make level mappings configurable
1 parent 196e83e commit 217e857

File tree

1 file changed

+127
-14
lines changed

1 file changed

+127
-14
lines changed

tracing-journald/src/lib.rs

+127-14
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,16 @@ mod socket;
6262
/// names by translating `.`s into `_`s, stripping leading `_`s and non-ascii-alphanumeric
6363
/// characters other than `_`, and upcasing.
6464
///
65-
/// Levels are mapped losslessly to journald `PRIORITY` values as follows:
65+
/// By default, levels are mapped losslessly to journald `PRIORITY` values as follows:
6666
///
6767
/// - `ERROR` => Error (3)
6868
/// - `WARN` => Warning (4)
6969
/// - `INFO` => Notice (5)
7070
/// - `DEBUG` => Informational (6)
7171
/// - `TRACE` => Debug (7)
7272
///
73+
/// These mappings can be changed with [`Subscriber::with_priority_mappings`]
74+
///
7375
/// The standard journald `CODE_LINE` and `CODE_FILE` fields are automatically emitted. A `TARGET`
7476
/// field is emitted containing the event's target.
7577
///
@@ -85,6 +87,7 @@ pub struct Subscriber {
8587
socket: UnixDatagram,
8688
field_prefix: Option<String>,
8789
syslog_identifier: String,
90+
priority_mappings: PriorityMappings,
8891
}
8992

9093
#[cfg(unix)]
@@ -109,6 +112,7 @@ impl Subscriber {
109112
.map(|n| n.to_string_lossy().into_owned())
110113
// If we fail to get the name of the current executable fall back to an empty string.
111114
.unwrap_or_else(String::new),
115+
priority_mappings: PriorityMappings::new(),
112116
};
113117
// Check that we can talk to journald, by sending empty payload which journald discards.
114118
// However if the socket didn't exist or if none listened we'd get an error here.
@@ -129,6 +133,12 @@ impl Subscriber {
129133
self
130134
}
131135

136+
/// Sets the mappings from the tracing level to the journald priorities.
137+
pub fn with_priority_mappings(mut self, mappings: PriorityMappings) -> Self {
138+
self.priority_mappings = mappings;
139+
self
140+
}
141+
132142
/// Sets the syslog identifier for this logger.
133143
///
134144
/// The syslog identifier comes from the classic syslog interface (`openlog()`
@@ -198,6 +208,20 @@ impl Subscriber {
198208
memfd::seal_fully(mem.as_raw_fd())?;
199209
socket::send_one_fd_to(&self.socket, mem.as_raw_fd(), JOURNALD_PATH)
200210
}
211+
212+
fn put_priority(&self, buf: &mut Vec<u8>, meta: &Metadata) {
213+
put_field_wellformed(
214+
buf,
215+
"PRIORITY",
216+
&[match *meta.level() {
217+
Level::ERROR => self.priority_mappings.error as u8,
218+
Level::WARN => self.priority_mappings.warn as u8,
219+
Level::INFO => self.priority_mappings.info as u8,
220+
Level::DEBUG => self.priority_mappings.debug as u8,
221+
Level::TRACE => self.priority_mappings.trace as u8,
222+
}],
223+
);
224+
}
201225
}
202226

203227
/// Construct a journald subscriber
@@ -252,7 +276,7 @@ where
252276
}
253277

254278
// Record event fields
255-
put_priority(&mut buf, event.metadata());
279+
self.put_priority(&mut buf, event.metadata());
256280
put_metadata(&mut buf, event.metadata(), None);
257281
put_field_length_encoded(&mut buf, "SYSLOG_IDENTIFIER", |buf| {
258282
write!(buf, "{}", self.syslog_identifier).unwrap()
@@ -339,18 +363,107 @@ impl Visit for EventVisitor<'_> {
339363
}
340364
}
341365

342-
fn put_priority(buf: &mut Vec<u8>, meta: &Metadata) {
343-
put_field_wellformed(
344-
buf,
345-
"PRIORITY",
346-
match *meta.level() {
347-
Level::ERROR => b"3",
348-
Level::WARN => b"4",
349-
Level::INFO => b"5",
350-
Level::DEBUG => b"6",
351-
Level::TRACE => b"7",
352-
},
353-
);
366+
// Descriptions and examples taken from the Archlinux wiki:
367+
// https://wiki.archlinux.org/title/Systemd/Journal#Priority_level
368+
/// A priority (in syslog called severity code) is used to mark the
369+
/// importance of a message.
370+
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
371+
#[repr(u8)]
372+
pub enum Priority {
373+
/// System is unusable.
374+
///
375+
/// Examples:
376+
///
377+
/// - severe Kernel BUG
378+
/// - systemd dumped core
379+
///
380+
/// This level should not be used by applications.
381+
Emergency = b'0',
382+
/// Should be corrected immediately.
383+
///
384+
/// Examples:
385+
///
386+
/// - Vital subsystem goes out of work, data loss:
387+
/// - `kernel: BUG: unable to handle kernel paging request at ffffc90403238ffc`
388+
Alert = b'1',
389+
/// Critical conditions
390+
///
391+
/// Examples:
392+
///
393+
/// - Crashe, coredumps
394+
/// - `systemd-coredump[25319]: Process 25310 (plugin-container) of user 1000 dumped core`
395+
Critical = b'2',
396+
/// Error conditions
397+
///
398+
/// Examples:
399+
///
400+
/// - Not severe error reported
401+
/// - `kernel: usb 1-3: 3:1: cannot get freq at ep 0x84, systemd[1]: Failed unmounting /var`
402+
/// - `libvirtd[1720]: internal error: Failed to initialize a valid firewall backend`
403+
Error = b'3',
404+
/// May indicate that an error will occur if action is not taken.
405+
///
406+
/// Examples:
407+
///
408+
/// - a non-root file system has only 1GB free
409+
/// - `org.freedesktop. Notifications[1860]: (process:5999): Gtk-WARNING **: Locale not supported by C library. Using the fallback 'C' locale`
410+
Warning = b'4',
411+
/// Events that are unusual, but not error conditions.
412+
///
413+
/// Examples:
414+
///
415+
/// - `systemd[1]: var.mount: Directory /var to mount over is not empty, mounting anyway`
416+
/// - `gcr-prompter[4997]: Gtk: GtkDialog mapped without a transient parent. This is discouraged`
417+
Notice = b'5',
418+
/// Normal operational messages that require no action.
419+
///
420+
/// Example: `lvm[585]: 7 logical volume(s) in volume group "archvg" now active`
421+
Informational = b'6',
422+
/// Information useful to developers for debugging the
423+
/// application.
424+
///
425+
/// Example: `kdeinit5[1900]: powerdevil: Scheduling inhibition from ":1.14" "firefox" with cookie 13 and reason "screen"`
426+
Debug = b'7',
427+
}
428+
429+
/// Mappings from the tracing levels to the journald priorities.
430+
#[derive(Debug, Clone)]
431+
pub struct PriorityMappings {
432+
/// Priority mapped to the `ERROR` level
433+
pub error: Priority,
434+
/// Priority mapped to the `WARN` level
435+
pub warn: Priority,
436+
/// Priority mapped to the `INFO` level
437+
pub info: Priority,
438+
/// Priority mapped to the `DEBUG` level
439+
pub debug: Priority,
440+
/// Priority mapped to the `TRACE` level
441+
pub trace: Priority,
442+
}
443+
444+
impl PriorityMappings {
445+
/// Create new default mappings:
446+
///
447+
/// - `tracing::Level::ERROR`: Error (3)
448+
/// - `tracing::Level::WARN`: Warning (4)
449+
/// - `tracing::Level::INFO`: Notice (5)
450+
/// - `tracing::Level::DEBUG`: Informational (6)
451+
/// - `tracing::Level::TRACE`: Debug (7)
452+
pub fn new() -> PriorityMappings {
453+
Self {
454+
error: Priority::Error,
455+
warn: Priority::Warning,
456+
info: Priority::Notice,
457+
debug: Priority::Informational,
458+
trace: Priority::Debug,
459+
}
460+
}
461+
}
462+
463+
impl Default for PriorityMappings {
464+
fn default() -> Self {
465+
Self::new()
466+
}
354467
}
355468

356469
fn put_metadata(buf: &mut Vec<u8>, meta: &Metadata, prefix: Option<&str>) {

0 commit comments

Comments
 (0)