Skip to content

Commit

Permalink
journald: add support for specifying syslog facility
Browse files Browse the repository at this point in the history
The syslog facility is optional and if it is not specified, it is not
included in JournalD message. The SyslogFacility enum contains all the
fields specified in syslog(3) for facility and numbers are mapped
using libc's definition.

I couldn't find why I needed to bitshift (line 466) the libc facility
values right to get the proper result, but this worked for me.
  • Loading branch information
oherrala committed Dec 29, 2022
1 parent 02903cb commit 3419e27
Showing 1 changed file with 110 additions and 0 deletions.
110 changes: 110 additions & 0 deletions tracing-journald/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pub struct Subscriber {
socket: UnixDatagram,
field_prefix: Option<String>,
syslog_identifier: String,
syslog_facility: Option<SyslogFacility>,
}

#[cfg(unix)]
Expand All @@ -109,6 +110,7 @@ impl Subscriber {
.map(|n| n.to_string_lossy().into_owned())
// If we fail to get the name of the current executable fall back to an empty string.
.unwrap_or_else(String::new),
syslog_facility: None,
};
// Check that we can talk to journald, by sending empty payload which journald discards.
// However if the socket didn't exist or if none listened we'd get an error here.
Expand Down Expand Up @@ -155,6 +157,31 @@ impl Subscriber {
&self.syslog_identifier
}

/// Sets the syslog facility for this logger.
///
/// The syslog facility comes from the classic syslog interface (`openlog()`
/// and `syslog()`). In syslog the facility argument is used to specify
/// what type of program is logging the message. This lets the configuration
/// file specify that messages from different facilities will be handled
/// differently. Systemd exposes it in the `SYSLOG_FACILITY` journal field,
/// and allows filtering log messages by syslog facility with `journalctl
/// --facility`.
///
/// See [Journal Fields](https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html)
/// and [journalctl](https://www.freedesktop.org/software/systemd/man/journalctl.html)
/// for more information.
///
/// If not set this field is left out.
pub fn with_syslog_facility(mut self, facility: SyslogFacility) -> Self {
self.syslog_facility = Some(facility);
self
}

/// Returns the syslog facility in use.
pub fn syslog_facility(&self) -> Option<SyslogFacility> {
self.syslog_facility
}

#[cfg(not(unix))]
fn send_payload(&self, _opayload: &[u8]) -> io::Result<()> {
Err(io::Error::new(
Expand Down Expand Up @@ -257,6 +284,9 @@ where
put_field_length_encoded(&mut buf, "SYSLOG_IDENTIFIER", |buf| {
write!(buf, "{}", self.syslog_identifier).unwrap()
});
if let Some(facility) = self.syslog_facility {
put_facility(&mut buf, facility);
}

event.record(&mut EventVisitor::new(
&mut buf,
Expand All @@ -268,6 +298,60 @@ where
}
}

/// The facility argument is used to specify what type of program is logging the
/// message. This lets the configuration file specify that messages from
/// different facilities will be handled differently.
#[derive(Copy, Clone)]
pub enum SyslogFacility {
/// security/authorization messages
Auth,
/// security/authorization messages (private)
Authpriv,
/// clock daemon (cron and at)
Cron,
/// system daemons without separate facility value
Daemon,
/// ftp daemon
Ftp,
/// kernel messages (these can't be generated from user
/// processes)
Kern,
///reserved for local use
Local0,
///reserved for local use
Local1,
///reserved for local use
Local2,
///reserved for local use
Local3,
///reserved for local use
Local4,
///reserved for local use
Local5,
///reserved for local use
Local6,
///reserved for local use
Local7,
/// line printer subsystem
Lpr,
/// mail subsystem
Mail,
/// USENET news subsystem
News,
/// messages generated internally by syslogd(8)
Syslog,
/// generic user-level messages
User,
/// UUCP subsystem
Uucp,
}

impl Default for SyslogFacility {
fn default() -> Self {
Self::User
}
}

struct SpanFields(Vec<u8>);

struct SpanVisitor<'a> {
Expand Down Expand Up @@ -353,6 +437,32 @@ fn put_priority(buf: &mut Vec<u8>, meta: &Metadata) {
);
}

fn put_facility(buf: &mut Vec<u8>, facility: SyslogFacility) {
let value = match facility {
SyslogFacility::Auth => libc::LOG_AUTH,
SyslogFacility::Authpriv => libc::LOG_AUTHPRIV,
SyslogFacility::Cron => libc::LOG_CRON,
SyslogFacility::Daemon => libc::LOG_DAEMON,
SyslogFacility::Ftp => libc::LOG_FTP,
SyslogFacility::Kern => libc::LOG_KERN,
SyslogFacility::Local0 => libc::LOG_LOCAL0,
SyslogFacility::Local1 => libc::LOG_LOCAL1,
SyslogFacility::Local2 => libc::LOG_LOCAL2,
SyslogFacility::Local3 => libc::LOG_LOCAL3,
SyslogFacility::Local4 => libc::LOG_LOCAL4,
SyslogFacility::Local5 => libc::LOG_LOCAL5,
SyslogFacility::Local6 => libc::LOG_LOCAL6,
SyslogFacility::Local7 => libc::LOG_LOCAL7,
SyslogFacility::Lpr => libc::LOG_LPR,
SyslogFacility::Mail => libc::LOG_MAIL,
SyslogFacility::News => libc::LOG_NEWS,
SyslogFacility::Syslog => libc::LOG_SYSLOG,
SyslogFacility::User => libc::LOG_USER,
SyslogFacility::Uucp => libc::LOG_UUCP,
};
put_field_wellformed(buf, "SYSLOG_FACILITY", format!("{}", value >> 3).as_bytes());
}

fn put_metadata(buf: &mut Vec<u8>, meta: &Metadata, prefix: Option<&str>) {
if let Some(prefix) = prefix {
write!(buf, "{}", prefix).unwrap();
Expand Down

0 comments on commit 3419e27

Please sign in to comment.