Skip to content

Commit 6eb08e5

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

File tree

1 file changed

+132
-14
lines changed

1 file changed

+132
-14
lines changed

tracing-journald/src/lib.rs

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

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

0 commit comments

Comments
 (0)