@@ -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
356469fn put_metadata ( buf : & mut Vec < u8 > , meta : & Metadata , prefix : Option < & str > ) {
0 commit comments