Skip to content

Commit 7673d7c

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

File tree

1 file changed

+169
-14
lines changed

1 file changed

+169
-14
lines changed

tracing-journald/src/lib.rs

+169-14
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ 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)
@@ -85,6 +85,7 @@ pub struct Subscriber {
8585
socket: UnixDatagram,
8686
field_prefix: Option<String>,
8787
syslog_identifier: String,
88+
priority_mappings: PriorityMappings,
8889
}
8990

9091
#[cfg(unix)]
@@ -109,6 +110,7 @@ impl Subscriber {
109110
.map(|n| n.to_string_lossy().into_owned())
110111
// If we fail to get the name of the current executable fall back to an empty string.
111112
.unwrap_or_else(String::new),
113+
priority_mappings: PriorityMappings::new(),
112114
};
113115
// Check that we can talk to journald, by sending empty payload which journald discards.
114116
// However if the socket didn't exist or if none listened we'd get an error here.
@@ -129,6 +131,12 @@ impl Subscriber {
129131
self
130132
}
131133

134+
/// Sets the mappings from the tracing level to the journald priorities.
135+
pub fn with_priority_mappings(mut self, mappings: PriorityMappings) -> Self {
136+
self.priority_mappings = mappings;
137+
self
138+
}
139+
132140
/// Sets the syslog identifier for this logger.
133141
///
134142
/// The syslog identifier comes from the classic syslog interface (`openlog()`
@@ -198,6 +206,20 @@ impl Subscriber {
198206
memfd::seal_fully(mem.as_raw_fd())?;
199207
socket::send_one_fd_to(&self.socket, mem.as_raw_fd(), JOURNALD_PATH)
200208
}
209+
210+
fn put_priority(&self, buf: &mut Vec<u8>, meta: &Metadata) {
211+
put_field_wellformed(
212+
buf,
213+
"PRIORITY",
214+
&[match *meta.level() {
215+
Level::ERROR => self.priority_mappings.error.as_u8(),
216+
Level::WARN => self.priority_mappings.warn.as_u8(),
217+
Level::INFO => self.priority_mappings.info.as_u8(),
218+
Level::DEBUG => self.priority_mappings.debug.as_u8(),
219+
Level::TRACE => self.priority_mappings.trace.as_u8(),
220+
}],
221+
);
222+
}
201223
}
202224

203225
/// Construct a journald subscriber
@@ -252,7 +274,7 @@ where
252274
}
253275

254276
// Record event fields
255-
put_priority(&mut buf, event.metadata());
277+
self.put_priority(&mut buf, event.metadata());
256278
put_metadata(&mut buf, event.metadata(), None);
257279
put_field_length_encoded(&mut buf, "SYSLOG_IDENTIFIER", |buf| {
258280
write!(buf, "{}", self.syslog_identifier).unwrap()
@@ -339,18 +361,151 @@ impl Visit for EventVisitor<'_> {
339361
}
340362
}
341363

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

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

0 commit comments

Comments
 (0)