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
20 changes: 19 additions & 1 deletion tracing-journald/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

#[cfg(unix)]
use std::os::unix::net::UnixDatagram;
use std::{fmt, io, io::Write};
use std::{collections::HashMap, fmt, io, io::Write};

use tracing_core::{
event::Event,
Expand Down Expand Up @@ -85,6 +85,7 @@ pub struct Subscriber {
socket: UnixDatagram,
field_prefix: Option<String>,
syslog_identifier: String,
additional_fields: HashMap<String, String>,
Finomnis marked this conversation as resolved.
Show resolved Hide resolved
}

#[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: HashMap::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,18 @@ impl Subscriber {
self
}

/// Adds a field that will get be passed to journald with every log entry.
///
/// 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.
pub fn with_journal_field(mut self, key: String, value: String) -> Self {
Finomnis marked this conversation as resolved.
Show resolved Hide resolved
Finomnis marked this conversation as resolved.
Show resolved Hide resolved
self.additional_fields.insert(key, value);
self
}

/// Returns the syslog identifier in use.
pub fn syslog_identifier(&self) -> &str {
&self.syslog_identifier
Expand Down Expand Up @@ -258,6 +272,10 @@ where
write!(buf, "{}", self.syslog_identifier).unwrap()
});

for (name, value) in &self.additional_fields {
put_field_length_encoded(&mut buf, name, |buf| write!(buf, "{}", value).unwrap())
}

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

#[test]
fn journal_fields() {
let sub = Subscriber::new()
.unwrap()
.with_field_prefix(None)
.with_journal_field("SYSLOG_FACILITY".to_string(), "17".to_string())
.with_journal_field("DOCUMENTATION".to_string(), "aBc".to_string());
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["DOCUMENTATION"], "aBc");
assert!(message["CODE_FILE"].as_text().is_some());
assert!(message["CODE_LINE"].as_text().is_some());
});
}

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