Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tracing-journald: allow custom journal fields #2708

Merged
merged 12 commits into from
Sep 5, 2023
31 changes: 31 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,
additional_fields: Vec<u8>,
}

#[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),
additional_fields: Vec::new(),
};
// 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 @@ -150,6 +152,34 @@ impl Subscriber {
self
}

/// Adds fields that will get be passed to journald with every log entry.
///
/// The input values of this function are interpreted as `(field, value)` pairs.
///
/// This can for example be used to configure the syslog 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.
Finomnis marked this conversation as resolved.
Show resolved Hide resolved
///
/// ```rust
/// # use tracing_journald::Subscriber;
/// let sub = Subscriber::new()
/// .unwrap()
/// .with_custom_fields([("SYSLOG_FACILITY", "17")]);
/// ```
///
pub fn with_custom_fields<T: AsRef<str>, U: AsRef<str>>(
Ralith marked this conversation as resolved.
Show resolved Hide resolved
mut self,
fields: impl IntoIterator<Item = (T, U)>,
) -> Self {
for (name, value) in fields {
put_field_length_encoded(&mut self.additional_fields, name.as_ref(), |buf| {
write!(buf, "{}", value.as_ref()).unwrap()
})
}
self
}

/// Returns the syslog identifier in use.
pub fn syslog_identifier(&self) -> &str {
&self.syslog_identifier
Expand Down Expand Up @@ -257,6 +287,7 @@ where
put_field_length_encoded(&mut buf, "SYSLOG_IDENTIFIER", |buf| {
write!(buf, "{}", self.syslog_identifier).unwrap()
});
buf.extend_from_slice(&self.additional_fields);

event.record(&mut EventVisitor::new(
&mut buf,
Expand Down
22 changes: 22 additions & 0 deletions tracing-journald/tests/journal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,28 @@ fn simple_metadata() {
});
}

#[test]
fn journal_fields() {
let sub = Subscriber::new()
.unwrap()
.with_field_prefix(None)
.with_custom_fields([("SYSLOG_FACILITY", "17")])
.with_custom_fields([("ABC", "dEf"), ("XYZ", "123")]);
with_journald_subscriber(sub, || {
info!(test.name = "journal_fields", "Hello World");

let message = retry_read_one_line_from_journal("journal_fields");
assert_eq!(message["MESSAGE"], "Hello World");
assert_eq!(message["PRIORITY"], "5");
assert_eq!(message["TARGET"], "journal");
assert_eq!(message["SYSLOG_FACILITY"], "17");
assert_eq!(message["ABC"], "dEf");
assert_eq!(message["XYZ"], "123");
assert!(message["CODE_FILE"].as_text().is_some());
assert!(message["CODE_LINE"].as_text().is_some());
});
}

#[test]
fn span_metadata() {
with_journald(|| {
Expand Down
Loading