1ORG.FREEDESKTOP.LOGCONTROL1o(r5g).freedesktop.LogContOrRoGl.1FREEDESKTOP.LOGCONTROL1(5)
2
3
4

NAME

6       org.freedesktop.LogControl1 - D-Bus interface to query and set logging
7       configuration
8

INTRODUCTION

10       org.freedesktop.LogControl1 is a generic interface that is intended to
11       be used by any daemon which allows the log level and target to be set
12       over D-Bus. It is implemented by various daemons that are part of the
13       systemd(1) suite.
14
15       It is assumed that those settings are global for the whole program, so
16       a fixed object path is used. The interface should always be available
17       under the path /org/freedesktop/LogControl1.
18

DESCRIPTION

20       The following interface is exposed:
21
22           node /org/freedesktop/LogControl1 {
23             interface org.freedesktop.LogControl1 {
24               properties:
25                 @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
26                 @org.freedesktop.systemd1.Privileged("true")
27                 readwrite s LogLevel = '...';
28                 @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
29                 @org.freedesktop.systemd1.Privileged("true")
30                 readwrite s LogTarget = '...';
31                 @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
32                 readonly s SyslogIdentifier = '...';
33             };
34             interface org.freedesktop.DBus.Peer { ... };
35             interface org.freedesktop.DBus.Introspectable { ... };
36             interface org.freedesktop.DBus.Properties { ... };
37           };
38
39
40
41
42
43
44   Properties
45       LogLevel describes the syslog(3)-style log-level, and should be one of
46       "emerg", "alert", "crit", "err", "warning", "notice", "info", "debug",
47       in order of increasing verbosity.
48
49       LogTarget describes the log target (mechanism). It should be one of
50       "console" (log to the console or standard output), "kmsg" (log to the
51       kernel ring buffer), "journal" (log to the journal natively, see
52       systemd-journald.service(8)), "syslog" (log using the syslog(3) call).
53
54       Those two properties are writable, so they may be set by sufficiently
55       privileged users.
56
57       SyslogIdentifier is a read-only property that shows the "syslog
58       identifier". It is a short string that identifies the program that is
59       the source of log messages that is passed to the syslog(3) call.
60

TOOLS

62       journalctl option -p/--priority= may be used to filter log messages by
63       log level, option -t/--identifier= may be used to by the syslog
64       identifier, and filters like "_TRANSPORT=syslog", "_TRANSPORT=journal",
65       and "_TRANSPORT=kernel" may be used to filter messages by the mechanism
66       through which they reached systemd-journald.
67
68       systemctl log-level and systemctl log-target verbs may be used to query
69       and set the LogLevel and LogTarget properties of the service manager.
70       systemctl service-log-level and systemctl service-log-target may
71       similarly be used for individual services. (Services must have the
72       BusName= property set and must implement the interface described here.
73       See systemd.service(5) for details about BusName=.)
74

EXAMPLE

76       Example 1. Create a simple listener on the bus that implements
77       LogControl1
78
79           /* SPDX-License-Identifier: MIT-0 */
80
81           /* Implements the LogControl1 interface as per specification:
82            * https://www.freedesktop.org/software/systemd/man/org.freedesktop.LogControl1.html
83            *
84            * Compile with 'cc logcontrol-example.c $(pkg-config --libs --cflags libsystemd)'
85            *
86            * To get and set properties via busctl:
87            *
88            * $ busctl --user get-property org.freedesktop.Example \
89            *                              /org/freedesktop/LogControl1 \
90            *                              org.freedesktop.LogControl1 \
91            *                              SyslogIdentifier
92            *   s "example"
93            * $ busctl --user get-property org.freedesktop.Example \
94            *                              /org/freedesktop/LogControl1 \
95            *                              org.freedesktop.LogControl1 \
96            *                              LogTarget
97            *   s "journal"
98            * $ busctl --user get-property org.freedesktop.Example \
99            *                              /org/freedesktop/LogControl1 \
100            *                              org.freedesktop.LogControl1 \
101            *                              LogLevel
102            *   s "info"
103            * $ busctl --user set-property org.freedesktop.Example \
104            *                              /org/freedesktop/LogControl1 \
105            *                              org.freedesktop.LogControl1 \
106            *                              LogLevel \
107            *                              "s" debug
108            * $ busctl --user get-property org.freedesktop.Example \
109            *                              /org/freedesktop/LogControl1 \
110            *                              org.freedesktop.LogControl1 \
111            *                              LogLevel
112            *   s "debug"
113            */
114
115           #include <errno.h>
116           #include <stdlib.h>
117           #include <stdio.h>
118           #include <syslog.h>
119           #include <systemd/sd-bus.h>
120           #include <systemd/sd-journal.h>
121
122           #define _cleanup_(f) __attribute__((cleanup(f)))
123
124           #define check(log_level, x) ({                  \
125             int _r = (x);                                 \
126             errno = _r < 0 ? -_r : 0;                     \
127             sd_journal_print((log_level), #x ": %m");     \
128             if (_r < 0)                                   \
129               return EXIT_FAILURE;                        \
130             })
131
132           typedef enum LogTarget {
133             LOG_TARGET_JOURNAL,
134             LOG_TARGET_KMSG,
135             LOG_TARGET_SYSLOG,
136             LOG_TARGET_CONSOLE,
137             _LOG_TARGET_MAX,
138           } LogTarget;
139
140           static const char* const log_target_table[_LOG_TARGET_MAX] = {
141             [LOG_TARGET_JOURNAL] = "journal",
142             [LOG_TARGET_KMSG]    = "kmsg",
143             [LOG_TARGET_SYSLOG]  = "syslog",
144             [LOG_TARGET_CONSOLE] = "console",
145           };
146
147           static const char* const log_level_table[LOG_DEBUG + 1] = {
148             [LOG_EMERG]   = "emerg",
149             [LOG_ALERT]   = "alert",
150             [LOG_CRIT]    = "crit",
151             [LOG_ERR]     = "err",
152             [LOG_WARNING] = "warning",
153             [LOG_NOTICE]  = "notice",
154             [LOG_INFO]    = "info",
155             [LOG_DEBUG]   = "debug",
156           };
157
158           typedef struct object {
159             const char *syslog_identifier;
160             LogTarget log_target;
161             int log_level;
162           } object;
163
164           static int property_get(
165                           sd_bus *bus,
166                           const char *path,
167                           const char *interface,
168                           const char *property,
169                           sd_bus_message *reply,
170                           void *userdata,
171                           sd_bus_error *error) {
172
173             object *o = userdata;
174
175             if (strcmp(property, "LogLevel") == 0)
176               return sd_bus_message_append(reply, "s", log_level_table[o->log_level]);
177
178             if (strcmp(property, "LogTarget") == 0)
179               return sd_bus_message_append(reply, "s", log_target_table[o->log_target]);
180
181             if (strcmp(property, "SyslogIdentifier") == 0)
182               return sd_bus_message_append(reply, "s", o->syslog_identifier);
183
184             return sd_bus_error_setf(error,
185                                      SD_BUS_ERROR_UNKNOWN_PROPERTY,
186                                      "Unknown property '%s'",
187                                      property);
188           }
189
190           static int property_set(
191                           sd_bus *bus,
192                           const char *path,
193                           const char *interface,
194                           const char *property,
195                           sd_bus_message *message,
196                           void *userdata,
197                           sd_bus_error *error) {
198
199             object *o = userdata;
200             const char *value;
201             int r;
202
203             r = sd_bus_message_read(message, "s", &value);
204             if (r < 0)
205               return r;
206
207             if (strcmp(property, "LogLevel") == 0) {
208               for (int i = 0; i < LOG_DEBUG + 1; i++)
209                 if (strcmp(value, log_level_table[i]) == 0) {
210                   o->log_level = i;
211                   return 0;
212                 }
213
214               return sd_bus_error_setf(error,
215                                        SD_BUS_ERROR_INVALID_ARGS,
216                                        "Invalid value for LogLevel: '%s'",
217                                        value);
218             }
219
220             if (strcmp(property, "LogTarget") == 0) {
221               for (LogTarget i = 0; i < _LOG_TARGET_MAX; i++)
222                 if (strcmp(value, log_target_table[i]) == 0) {
223                   o->log_target = i;
224                   return 0;
225                 }
226
227               return sd_bus_error_setf(error,
228                                        SD_BUS_ERROR_INVALID_ARGS,
229                                        "Invalid value for LogTarget: '%s'",
230                                        value);
231             }
232
233             return sd_bus_error_setf(error,
234                                      SD_BUS_ERROR_UNKNOWN_PROPERTY,
235                                      "Unknown property '%s'",
236                                      property);
237           }
238
239           /* https://www.freedesktop.org/software/systemd/man/sd_bus_add_object.html
240            */
241           static const sd_bus_vtable vtable[] = {
242             SD_BUS_VTABLE_START(0),
243             SD_BUS_WRITABLE_PROPERTY(
244               "LogLevel", "s",
245               property_get, property_set,
246               0,
247               0),
248             SD_BUS_WRITABLE_PROPERTY(
249               "LogTarget", "s",
250               property_get, property_set,
251               0,
252               0),
253             SD_BUS_PROPERTY(
254               "SyslogIdentifier", "s",
255               property_get,
256               0,
257               SD_BUS_VTABLE_PROPERTY_CONST),
258             SD_BUS_VTABLE_END
259           };
260
261           int main(int argc, char **argv) {
262             /* The bus should be relinquished before the program terminates. The cleanup
263              * attribute allows us to do it nicely and cleanly whenever we exit the
264              * block.
265              */
266             _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
267
268             object o = {
269               .log_level = LOG_INFO,
270               .log_target = LOG_TARGET_JOURNAL,
271               .syslog_identifier = "example",
272             };
273
274             /* Acquire a connection to the bus, letting the library work out the details.
275              * https://www.freedesktop.org/software/systemd/man/sd_bus_default.html
276              */
277             check(o.log_level, sd_bus_default(&bus));
278
279             /* Publish an interface on the bus, specifying our well-known object access
280              * path and public interface name.
281              * https://www.freedesktop.org/software/systemd/man/sd_bus_add_object.html
282              * https://dbus.freedesktop.org/doc/dbus-tutorial.html
283              */
284             check(o.log_level, sd_bus_add_object_vtable(bus, NULL,
285                                                         "/org/freedesktop/LogControl1",
286                                                         "org.freedesktop.LogControl1",
287                                                         vtable,
288                                                         &o));
289
290             /* By default the service is assigned an ephemeral name. Also add a fixed
291              * one, so that clients know whom to call.
292              * https://www.freedesktop.org/software/systemd/man/sd_bus_request_name.html
293              */
294             check(o.log_level, sd_bus_request_name(bus, "org.freedesktop.Example", 0));
295
296             for (;;) {
297               /* https://www.freedesktop.org/software/systemd/man/sd_bus_wait.html
298                */
299               check(o.log_level, sd_bus_wait(bus, UINT64_MAX));
300               /* https://www.freedesktop.org/software/systemd/man/sd_bus_process.html
301                */
302               check(o.log_level, sd_bus_process(bus, NULL));
303             }
304
305             /* https://www.freedesktop.org/software/systemd/man/sd_bus_release_name.html
306              */
307             check(o.log_level, sd_bus_release_name(bus, "org.freedesktop.Example"));
308
309             return 0;
310           }
311
312       This creates a simple server on the bus. It implements the LogControl1
313       interface by providing the required properties and allowing to set the
314       writable ones. It logs at the configured log level using
315       sd_journal_print(3).
316

SEE ALSO

318       systemd(1), journalctl(1), systemctl(1), systemd.service(5), syslog(3)
319
320
321
322systemd 253                                     ORG.FREEDESKTOP.LOGCONTROL1(5)
Impressum