1ORG.FREEDESKTOP.LOGCONTROL1o(r5g).freedesktop.LogContOrRoGl.1FREEDESKTOP.LOGCONTROL1(5)
2
3
4
6 org.freedesktop.LogControl1 - D-Bus interface to query and set logging
7 configuration
8
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
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
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
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
318 systemd(1), journalctl(1), systemctl(1), systemd.service(5), syslog(3)
319
320
321
322systemd 253 ORG.FREEDESKTOP.LOGCONTROL1(5)