]> git.ipfire.org Git - thirdparty/systemd.git/blame - docs/JOURNAL_NATIVE_PROTOCOL.md
man: add self-contained example of notify protocol
[thirdparty/systemd.git] / docs / JOURNAL_NATIVE_PROTOCOL.md
CommitLineData
1a80f4e0
LP
1---
2title: Native Journal Protocol
3category: Interfaces
4layout: default
0aff7b75 5SPDX-License-Identifier: LGPL-2.1-or-later
1a80f4e0
LP
6---
7
8# Native Journal Protocol
9
10`systemd-journald.service` accepts log data via various protocols:
11
12* Classic RFC3164 BSD syslog via the `/dev/log` socket
13* STDOUT/STDERR of programs via `StandardOutput=journal` + `StandardError=journal` in service files (both of which are default settings)
14* Kernel log messages via the `/dev/kmsg` device node
15* Audit records via the kernel's audit subsystem
16* Structured log messages via `journald`'s native protocol
17
18The latter is what this document is about: if you are developing a program and
19want to pass structured log data to `journald`, it's the Journal's native
f223fd6a 20protocol that you want to use. The systemd project provides the
1a80f4e0
LP
21[`sd_journal_print(3)`](https://www.freedesktop.org/software/systemd/man/sd_journal_print.html)
22API that implements the client side of this protocol. This document explains
23what this interface does behind the scenes, in case you'd like to implement a
24client for it yourself, without linking to `libsystemd` — for example because
25you work in a programming language other than C or otherwise want to avoid the
26dependency.
27
28## Basics
29
30The native protocol of `journald` is spoken on the
31`/run/systemd/journal/socket` `AF_UNIX`/`SOCK_DGRAM` socket on which
32`systemd-journald.service` listens. Each datagram sent to this socket
33encapsulates one journal entry that shall be written. Since datagrams are
34subject to a size limit and we want to allow large journal entries, datagrams
35sent over this socket may come in one of two formats:
36
37* A datagram with the literal journal entry data as payload, without
38 any file descriptors attached.
39
40* A datagram with an empty payload, but with a single
41 [`memfd`](https://man7.org/linux/man-pages/man2/memfd_create.2.html)
42 file descriptor that contains the literal journal entry data.
43
44Other combinations are not permitted, i.e. datagrams with both payload and file
45descriptors, or datagrams with neither, or more than one file descriptor. Such
46datagrams are ignored. The `memfd` file descriptor should be fully sealed. The
47binary format in the datagram payload and in the `memfd` memory is
48identical. Typically a client would attempt to first send the data as datagram
49payload, but if this fails with an `EMSGSIZE` error it would immediately retry
50via the `memfd` logic.
51
52A client probably should bump up the `SO_SNDBUF` socket option of its `AF_UNIX`
53socket towards `journald` in order to delay blocking I/O as much as possible.
54
55## Data Format
56
57Each datagram should consist of a number of environment-like key/value
58assignments. Unlike environment variable assignments the value may contain NUL
59bytes however, as well as any other binary data. Keys may not include the `=`
60or newline characters (or any other control characters or non-ASCII characters)
61and may not be empty.
62
4bb37359 63Serialization into the datagram payload or `memfd` is straightforward: each
1a80f4e0
LP
64key/value pair is serialized via one of two methods:
65
66* The first method inserts a `=` character between key and value, and suffixes
67the result with `\n` (i.e. the newline character, ASCII code 10). Example: a
68key `FOO` with a value `BAR` is serialized `F`, `O`, `O`, `=`, `B`, `A`, `R`,
69`\n`.
70
71* The second method should be used if the value of a field contains a `\n`
72byte. In this case, the key name is serialized as is, followed by a `\n`
da890466 73character, followed by a (non-aligned) little-endian unsigned 64-bit integer
1a80f4e0
LP
74encoding the size of the value, followed by the literal value data, followed by
75`\n`. Example: a key `FOO` with a value `BAR` may be serialized using this
76second method as: `F`, `O`, `O`, `\n`, `\003`, `\000`, `\000`, `\000`, `\000`,
77`\000`, `\000`, `\000`, `B`, `A`, `R`, `\n`.
78
79If the value of a key/value pair contains a newline character (`\n`), it *must*
80be serialized using the second method. If it does not, either method is
81permitted. However, it is generally recommended to use the first method if
82possible for all key/value pairs where applicable since the generated datagrams
83are easily recognized and understood by the human eye this way, without any
84manual binary decoding — which improves the debugging experience a lot, in
85particular with tools such as `strace` that can show datagram content as text
86dump. After all, log messages are highly relevant for debugging programs, hence
87optimizing log traffic for readability without special tools is generally
88desirable.
89
90Note that keys that begin with `_` have special semantics in `journald`: they
91are *trusted* and implicitly appended by `journald` on the receiving
92side. Clients should not send them — if they do anyway, they will be ignored.
93
94The most important key/value pair to send is `MESSAGE=`, as that contains the
95actual log message text. Other relevant keys a client should send in most cases
96are `PRIORITY=`, `CODE_FILE=`, `CODE_LINE=`, `CODE_FUNC=`, `ERRNO=`. It's
97recommended to generate these fields implicitly on the client side. For further
98information see the [relevant documentation of these
99fields](https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html).
100
101The order in which the fields are serialized within one datagram is undefined
102and may be freely chosen by the client. The server side might or might not
103retain or reorder it when writing it to the Journal.
104
105Some programs might generate multi-line log messages (e.g. a stack unwinder
106generating log output about a stack trace, with one line for each stack
107frame). It's highly recommended to send these as a single datagram, using a
108single `MESSAGE=` field with embedded newline characters between the lines (the
109second serialization method described above must hence be used for this
110field). If possible do not split up individual events into multiple Journal
111events that might then be processed and written into the Journal as separate
112entries. The Journal toolchain is capable of handling multi-line log entries
113just fine, and it's generally preferred to have a single set of metadata fields
114associated with each multi-line message.
115
116Note that the same keys may be used multiple times within the same datagram,
117with different values. The Journal supports this and will write such entries to
118disk without complaining. This is useful for associating a single log entry
119with multiple suitable objects of the same type at once. This should only be
120used for specific Journal fields however, where this is expected. Do not use
121this for Journal fields where this is not expected and where code reasonably
122assumes per-event uniqueness of the keys. In most cases code that consumes and
123displays log entries is likely to ignore such non-unique fields or only
124consider the first of the specified values. Specifically, if a Journal entry
125contains multiple `MESSAGE=` fields, likely only the first one is
126displayed. Note that a well-written logging client library thus will not use a
127plain dictionary for accepting structured log metadata, but rather a data
128structure that allows non-unique keys, for example an array, or a dictionary
129that optionally maps to a set of values instead of a single value.
130
131## Example Datagram
132
133Here's an encoded message, with various common fields, all encoded according to
134the first serialization method, with the exception of one, where the value
135contains a newline character, and thus the second method is needed to be used.
136
137```
138PRIORITY=3\n
139SYSLOG_FACILITY=3\n
140CODE_FILE=src/foobar.c\n
141CODE_LINE=77\n
142BINARY_BLOB\n
143\004\000\000\000\000\000\000\000xx\nx\n
144CODE_FUNC=some_func\n
145SYSLOG_IDENTIFIER=footool\n
146MESSAGE=Something happened.\n
147```
148
149(Lines are broken here after each `\n` to make things more readable. C-style
150backslash escaping is used.)
151
152## Automatic Protocol Upgrading
153
154It might be wise to automatically upgrade to logging via the Journal's native
155protocol in clients that previously used the BSD syslog protocol. Behaviour in
156this case should be pretty obvious: try connecting a socket to
157`/run/systemd/journal/socket` first (on success use the native Journal
158protocol), and if that fails fall back to `/dev/log` (and use the BSD syslog
159protocol).
160
161Programs normally logging to STDERR might also choose to upgrade to native
162Journal logging in case they are invoked via systemd's service logic, where
163STDOUT and STDERR are going to the Journal anyway. By preferring the native
164protocol over STDERR-based logging, structured metadata can be passed along,
165including priority information and more — which is not available on STDERR
166based logging. If a program wants to detect automatically whether its STDERR is
167connected to the Journal's stream transport, look for the `$JOURNAL_STREAM`
168environment variable. The systemd service logic sets this variable to a
169colon-separated pair of device and inode number (formatted in decimal ASCII) of
170the STDERR file descriptor. If the `.st_dev` and `.st_ino` fields of the
171`struct stat` data returned by `fstat(STDERR_FILENO, …)` match these values a
172program can be sure its STDERR is connected to the Journal, and may then opt to
173upgrade to the native Journal protocol via an `AF_UNIX` socket of its own, and
174cease to use STDERR.
175
176Why bother with this environment variable check? A service program invoked by
177systemd might employ shell-style I/O redirection on invoked subprograms, and
178those should likely not upgrade to the native Journal protocol, but instead
179continue to use the redirected file descriptors passed to them. Thus, by
180comparing the device and inode number of the actual STDERR file descriptor with
181the one the service manager passed, one can make sure that no I/O redirection
182took place for the current program.
183
184## Alternative Implementations
185
186If you are looking for alternative implementations of this protocol (besides
187systemd's own in `sd_journal_print()`), consider
df1f621b 188[GLib's](https://gitlab.gnome.org/GNOME/glib/-/blob/main/glib/gmessages.c) or
1a80f4e0
LP
189[`dbus-broker`'s](https://github.com/bus1/dbus-broker/blob/main/src/util/log.c).
190
191And that's already all there is to it.