Skip to content

Commit 587b5e5

Browse files
swsnrhawkw
authored andcommitted
journald: Set syslog identifier (#1822)
Set the `SYSLOG_IDENTIFIER` field on all events. I noticed that the subscriber didn't do this so far. ## Motivation The identifier is used with `journalctl -t`, and while it's normally better to filter by unit with `journalctl -u` the identifier is still nice for processes that are not started through systemd units. Upstream does this as well, see [here]: ![grafik](https://user-images.githubusercontent.com/224922/148660479-9525b21e-547f-4787-9bb7-db933963041a.png) `program_invocation_short_name` is a glibc variable which holds the file name of the current executable; I tried to replicate this behaviour in Rust. ## Solution Add a syslog identifier field to the subscriber, defaulting to the filename of the current executable, and write this value as `SYSLOG_IDENTIFIER` with every event. It's not written for spans, because it's a global value and inevitably the same for each span. [here]: https://github.com/systemd/systemd/blob/81218ac1e14b4b50b4337938bcf55cacc76f0728/src/libsystemd/sd-journal/journal-send.c#L270
1 parent 13771cb commit 587b5e5

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

tracing-journald/src/lib.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub struct Layer {
8484
#[cfg(unix)]
8585
socket: UnixDatagram,
8686
field_prefix: Option<String>,
87+
syslog_identifier: String,
8788
}
8889

8990
#[cfg(unix)]
@@ -101,6 +102,13 @@ impl Layer {
101102
let layer = Self {
102103
socket,
103104
field_prefix: Some("F".into()),
105+
syslog_identifier: std::env::current_exe()
106+
.ok()
107+
.as_ref()
108+
.and_then(|p| p.file_name())
109+
.map(|n| n.to_string_lossy().into_owned())
110+
// If we fail to get the name of the current executable fall back to an empty string.
111+
.unwrap_or_else(String::new),
104112
};
105113
// Check that we can talk to journald, by sending empty payload which journald discards.
106114
// However if the socket didn't exist or if none listened we'd get an error here.
@@ -121,6 +129,32 @@ impl Layer {
121129
self
122130
}
123131

132+
/// Sets the syslog identifier for this logger.
133+
///
134+
/// The syslog identifier comes from the classic syslog interface (`openlog()`
135+
/// and `syslog()`) and tags log entries with a given identifier.
136+
/// Systemd exposes it in the `SYSLOG_IDENTIFIER` journal field, and allows
137+
/// filtering log messages by syslog identifier with `journalctl -t`.
138+
/// Unlike the unit (`journalctl -u`) this field is not trusted, i.e. applications
139+
/// can set it freely, and use it e.g. to further categorize log entries emitted under
140+
/// the same systemd unit or in the same process. It also allows to filter for log
141+
/// entries of processes not started in their own unit.
142+
///
143+
/// See [Journal Fields](https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html)
144+
/// and [journalctl](https://www.freedesktop.org/software/systemd/man/journalctl.html)
145+
/// for more information.
146+
///
147+
/// Defaults to the file name of the executable of the current process, if any.
148+
pub fn with_syslog_identifier(mut self, identifier: String) -> Self {
149+
self.syslog_identifier = identifier;
150+
self
151+
}
152+
153+
/// Returns the syslog identifier in use.
154+
pub fn syslog_identifier(&self) -> &str {
155+
&self.syslog_identifier
156+
}
157+
124158
#[cfg(not(unix))]
125159
fn send_payload(&self, _opayload: &[u8]) -> io::Result<()> {
126160
Err(io::Error::new(
@@ -224,6 +258,10 @@ where
224258

225259
// Record event fields
226260
put_metadata(&mut buf, event.metadata(), None);
261+
put_field_length_encoded(&mut buf, "SYSLOG_IDENTIFIER", |buf| {
262+
write!(buf, "{}", self.syslog_identifier).unwrap()
263+
});
264+
227265
event.record(&mut EventVisitor::new(
228266
&mut buf,
229267
self.field_prefix.as_ref().map(|x| &x[..]),

0 commit comments

Comments
 (0)