Skip to content

Commit

Permalink
journald: allow custom journal fields (#2708)
Browse files Browse the repository at this point in the history
It's currently not possible to customize how messages will get send to journald.

This became apparent in #2425, where first a specific API got designed, but then
it was decided that users should not get restricted in only a subset of fields,
but should be able to simply choose by themselves what fields get set with what
values.

So in a sense, this is the successor/rework of #2425.

Allow custom fields to be set in tracing-journald.

- [x] How should we deal with fields that also get supplied by other options?
  For example, setting `SYSLOG_IDENTIFIER` here and also setting
  `.with_syslog_identifier()` will send said field twice, potentially with
  differing values. Is that a problem?
    - Answer: No, this is not a problem.

Closes #2425
  • Loading branch information
Finomnis authored and hawkw committed Oct 1, 2023
1 parent b8180dd commit 7666f6c
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
37 changes: 37 additions & 0 deletions tracing-journald/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pub struct Layer {
socket: UnixDatagram,
field_prefix: Option<String>,
syslog_identifier: String,
additional_fields: Vec<u8>,
}

#[cfg(unix)]
Expand All @@ -107,6 +108,7 @@ impl Layer {
.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 @@ -148,6 +150,40 @@ impl Layer {
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.
///
/// Fields specified using this method will be added to the journald
/// message alongside fields generated from the event's fields, its
/// metadata, and the span context. If the name of a field provided using
/// this method is the same as the name of a field generated by the
/// layer, both fields will be sent to journald.
///
/// ```no_run
/// # use tracing_journald::Layer;
/// let layer = Layer::new()
/// .unwrap()
/// .with_custom_fields([("SYSLOG_FACILITY", "17")]);
/// ```
///
pub fn with_custom_fields<T: AsRef<str>, U: AsRef<[u8]>>(
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| {
buf.extend_from_slice(value.as_ref())
})
}
self
}

/// Returns the syslog identifier in use.
pub fn syslog_identifier(&self) -> &str {
&self.syslog_identifier
Expand Down Expand Up @@ -255,6 +291,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 @@ -238,6 +238,28 @@ fn simple_metadata() {
});
}

#[test]
fn journal_fields() {
let sub = Layer::new()
.unwrap()
.with_field_prefix(None)
.with_custom_fields([("SYSLOG_FACILITY", "17")])
.with_custom_fields([("ABC", "dEf"), ("XYZ", "123")]);
with_journald_layer(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

0 comments on commit 7666f6c

Please sign in to comment.