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