1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Copyright (C) 2006 - 2012 Red Hat, Inc.
19 * Copyright (C) 2006 - 2008 Novell, Inc.
22 #include "nm-default.h"
35 #if defined (NO_SYSTEMD_JOURNAL) && defined (SYSTEMD_JOURNAL)
36 #undef SYSTEMD_JOURNAL
37 #define SYSTEMD_JOURNAL 0
41 #define SD_JOURNAL_SUPPRESS_LOCATION
42 #include <systemd/sd-journal.h>
45 #include "nm-errors.h"
46 #include "nm-core-utils.h"
49 LOG_FORMAT_FLAG_NONE = 0,
50 LOG_FORMAT_FLAG_TIMESTAMP_DEBUG = (1LL << 0),
51 LOG_FORMAT_FLAG_TIMESTAMP_INFO = (1LL << 1),
52 LOG_FORMAT_FLAG_TIMESTAMP_ERROR = (1LL << 2),
53 LOG_FORMAT_FLAG_LOCATION_DEBUG = (1LL << 3),
54 LOG_FORMAT_FLAG_LOCATION_INFO = (1LL << 4),
55 LOG_FORMAT_FLAG_LOCATION_ERROR = (1LL << 5),
56 LOG_FORMAT_FLAG_ALIGN_LOCATION = (1LL << 6),
58 _LOG_FORMAT_FLAG_TIMESTAMP = LOG_FORMAT_FLAG_TIMESTAMP_DEBUG |
59 LOG_FORMAT_FLAG_TIMESTAMP_INFO |
60 LOG_FORMAT_FLAG_TIMESTAMP_ERROR,
61 _LOG_FORMAT_FLAG_LOCATION = LOG_FORMAT_FLAG_LOCATION_DEBUG |
62 LOG_FORMAT_FLAG_LOCATION_INFO |
63 LOG_FORMAT_FLAG_LOCATION_ERROR,
65 _LOG_FORMAT_FLAG_LEVEL_DEBUG = LOG_FORMAT_FLAG_TIMESTAMP_DEBUG |
66 LOG_FORMAT_FLAG_LOCATION_DEBUG,
67 _LOG_FORMAT_FLAG_LEVEL_INFO = LOG_FORMAT_FLAG_TIMESTAMP_INFO |
68 LOG_FORMAT_FLAG_LOCATION_INFO,
69 _LOG_FORMAT_FLAG_LEVEL_ERROR = LOG_FORMAT_FLAG_TIMESTAMP_ERROR |
70 LOG_FORMAT_FLAG_LOCATION_ERROR,
72 _LOG_FORMAT_FLAG_SYSLOG = _LOG_FORMAT_FLAG_TIMESTAMP |
73 LOG_FORMAT_FLAG_LOCATION_DEBUG |
74 LOG_FORMAT_FLAG_LOCATION_ERROR |
75 LOG_FORMAT_FLAG_ALIGN_LOCATION,
77 _LOG_FORMAT_FLAG_DEFAULT = _LOG_FORMAT_FLAG_TIMESTAMP,
80 void (*_nm_logging_clear_platform_logging_cache) (void);
83 nm_log_handler (const gchar *log_domain,
95 const char *level_str;
97 GLogLevelFlags g_log_level;
98 LogFormatFlags log_format_level;
102 NMLogLevel log_level;
103 NMLogDomain logging[_LOGL_N_REAL];
104 gboolean logging_set_up;
105 LogFormatFlags log_format_flags;
111 char *logging_domains_to_string;
112 const LogLevelDesc level_desc[_LOGL_N];
114 #define _DOMAIN_DESC_LEN 37
115 /* Would be nice to use C99 flexible array member here,
116 * but that feature doesn't seem well supported. */
117 const LogDesc domain_desc[_DOMAIN_DESC_LEN];
119 .log_level = LOGL_INFO,
120 .log_backend = LOG_BACKEND_GLIB,
121 .log_format_flags = _LOG_FORMAT_FLAG_DEFAULT,
123 [LOGL_TRACE] = { "TRACE", "<trace>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, _LOG_FORMAT_FLAG_LEVEL_DEBUG },
124 [LOGL_DEBUG] = { "DEBUG", "<debug>", LOG_INFO, G_LOG_LEVEL_DEBUG, _LOG_FORMAT_FLAG_LEVEL_DEBUG },
125 [LOGL_INFO] = { "INFO", "<info>", LOG_INFO, G_LOG_LEVEL_INFO, _LOG_FORMAT_FLAG_LEVEL_INFO },
126 [LOGL_WARN] = { "WARN", "<warn>", LOG_WARNING, G_LOG_LEVEL_MESSAGE, _LOG_FORMAT_FLAG_LEVEL_INFO },
127 [LOGL_ERR] = { "ERR", "<error>", LOG_ERR, G_LOG_LEVEL_MESSAGE, _LOG_FORMAT_FLAG_LEVEL_ERROR },
128 [_LOGL_OFF] = { "OFF", NULL, 0, 0, 0 },
129 [_LOGL_KEEP] = { "KEEP", NULL, 0, 0, 0 },
132 { LOGD_PLATFORM, "PLATFORM" },
133 { LOGD_RFKILL, "RFKILL" },
134 { LOGD_ETHER, "ETHER" },
135 { LOGD_WIFI, "WIFI" },
138 { LOGD_DHCP4, "DHCP4" },
139 { LOGD_DHCP6, "DHCP6" },
141 { LOGD_WIFI_SCAN, "WIFI_SCAN" },
144 { LOGD_AUTOIP4, "AUTOIP4" },
147 { LOGD_SHARING, "SHARING" },
148 { LOGD_SUPPLICANT,"SUPPLICANT" },
149 { LOGD_AGENTS, "AGENTS" },
150 { LOGD_SETTINGS, "SETTINGS" },
151 { LOGD_SUSPEND, "SUSPEND" },
152 { LOGD_CORE, "CORE" },
153 { LOGD_DEVICE, "DEVICE" },
154 { LOGD_OLPC, "OLPC" },
155 { LOGD_INFINIBAND,"INFINIBAND" },
156 { LOGD_FIREWALL, "FIREWALL" },
157 { LOGD_ADSL, "ADSL" },
158 { LOGD_BOND, "BOND" },
159 { LOGD_VLAN, "VLAN" },
160 { LOGD_BRIDGE, "BRIDGE" },
161 { LOGD_DBUS_PROPS,"DBUS_PROPS" },
162 { LOGD_TEAM, "TEAM" },
163 { LOGD_CONCHECK, "CONCHECK" },
165 { LOGD_DISPATCH, "DISPATCH" },
166 { LOGD_AUDIT, "AUDIT" },
167 { LOGD_SYSTEMD, "SYSTEMD" },
169 /* keep _DOMAIN_DESC_LEN in sync */
173 /* We have more then 32 logging domains. Assert that it compiles to a 64 bit sized enum */
174 G_STATIC_ASSERT (sizeof (NMLogDomain) >= sizeof (guint64));
176 /* Combined domains */
177 #define LOGD_ALL_STRING "ALL"
178 #define LOGD_DEFAULT_STRING "DEFAULT"
179 #define LOGD_DHCP_STRING "DHCP"
180 #define LOGD_IP_STRING "IP"
182 /************************************************************************/
184 static char *_domains_to_string (gboolean include_level_override);
186 /************************************************************************/
189 _ensure_initialized (void)
191 if (G_UNLIKELY (!global.logging_set_up)) {
194 nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL);
196 /* must ensure that errno is not modified. */
202 match_log_level (const char *level,
203 NMLogLevel *out_level,
208 for (i = 0; i < G_N_ELEMENTS (global.level_desc); i++) {
209 if (!g_ascii_strcasecmp (global.level_desc[i].name, level)) {
215 g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_LOG_LEVEL,
216 _("Unknown log level '%s'"), level);
221 nm_logging_setup (const char *level,
226 GString *unrecognized = NULL;
227 NMLogDomain new_logging[G_N_ELEMENTS (global.logging)];
228 NMLogLevel new_log_level = global.log_level;
231 gboolean had_platform_debug;
232 gs_free char *domains_free = NULL;
234 g_return_val_if_fail (!bad_domains || !*bad_domains, FALSE);
235 g_return_val_if_fail (!error || !*error, FALSE);
238 if (!domains || !*domains) {
239 domains = global.logging_set_up
240 ? (domains_free = _domains_to_string (FALSE))
241 : LOGD_DEFAULT_STRING;
244 global.logging_set_up = TRUE;
246 for (i = 0; i < G_N_ELEMENTS (new_logging); i++)
250 if (level && *level) {
251 if (!match_log_level (level, &new_log_level, error))
253 if (new_log_level == _LOGL_KEEP) {
254 new_log_level = global.log_level;
255 for (i = 0; i < G_N_ELEMENTS (new_logging); i++)
256 new_logging[i] = global.logging[i];
260 tmp = g_strsplit_set (domains, ", ", 0);
261 for (iter = tmp; iter && *iter; iter++) {
262 const LogDesc *diter;
263 NMLogLevel domain_log_level;
270 p = strchr (*iter, ':');
273 if (!match_log_level (p + 1, &domain_log_level, error)) {
278 domain_log_level = new_log_level;
282 /* Check for combined domains */
283 if (!g_ascii_strcasecmp (*iter, LOGD_ALL_STRING))
285 else if (!g_ascii_strcasecmp (*iter, LOGD_DEFAULT_STRING))
287 else if (!g_ascii_strcasecmp (*iter, LOGD_DHCP_STRING))
289 else if (!g_ascii_strcasecmp (*iter, LOGD_IP_STRING))
292 /* Check for compatibility domains */
293 else if (!g_ascii_strcasecmp (*iter, "HW"))
294 bits = LOGD_PLATFORM;
295 else if (!g_ascii_strcasecmp (*iter, "WIMAX"))
299 for (diter = &global.domain_desc[0]; diter->name; diter++) {
300 if (!g_ascii_strcasecmp (diter->name, *iter)) {
308 g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_LOG_DOMAIN,
309 _("Unknown log domain '%s'"), *iter);
314 g_string_append (unrecognized, ", ");
316 unrecognized = g_string_new (NULL);
317 g_string_append (unrecognized, *iter);
322 if (domain_log_level == _LOGL_KEEP) {
323 for (i = 0; i < G_N_ELEMENTS (new_logging); i++)
324 new_logging[i] = (new_logging[i] & ~bits) | (global.logging[i] & bits);
326 for (i = 0; i < G_N_ELEMENTS (new_logging); i++) {
327 if (i < domain_log_level)
328 new_logging[i] &= ~bits;
330 new_logging[i] |= bits;
336 g_clear_pointer (&global.logging_domains_to_string, g_free);
338 had_platform_debug = nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM);
340 global.log_level = new_log_level;
341 for (i = 0; i < G_N_ELEMENTS (new_logging); i++)
342 global.logging[i] = new_logging[i];
344 if ( had_platform_debug
345 && _nm_logging_clear_platform_logging_cache
346 && !nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
347 /* when debug logging is enabled, platform will cache all access to
348 * sysctl. When the user disables debug-logging, we want to clear that
349 * cache right away. */
350 _nm_logging_clear_platform_logging_cache ();
354 *bad_domains = g_string_free (unrecognized, FALSE);
360 nm_logging_level_to_string (void)
362 return global.level_desc[global.log_level].name;
366 nm_logging_all_levels_to_string (void)
370 if (G_UNLIKELY (!str)) {
373 str = g_string_new (NULL);
374 for (i = 0; i < G_N_ELEMENTS (global.level_desc); i++) {
376 g_string_append_c (str, ',');
377 g_string_append (str, global.level_desc[i].name);
385 nm_logging_domains_to_string (void)
387 _ensure_initialized ();
389 if (G_UNLIKELY (!global.logging_domains_to_string))
390 global.logging_domains_to_string = _domains_to_string (TRUE);
392 return global.logging_domains_to_string;
396 _domains_to_string (gboolean include_level_override)
398 const LogDesc *diter;
402 /* We don't just return g_strdup (global.log_domains) because we want to expand
403 * "DEFAULT" and "ALL".
406 str = g_string_sized_new (75);
407 for (diter = &global.domain_desc[0]; diter->name; diter++) {
408 /* If it's set for any lower level, it will also be set for LOGL_ERR */
409 if (!(diter->num & global.logging[LOGL_ERR]))
413 g_string_append_c (str, ',');
414 g_string_append (str, diter->name);
416 if (!include_level_override)
419 /* Check if it's logging at a lower level than the default. */
420 for (i = 0; i < global.log_level; i++) {
421 if (diter->num & global.logging[i]) {
422 g_string_append_printf (str, ":%s", global.level_desc[i].name);
426 /* Check if it's logging at a higher level than the default. */
427 if (!(diter->num & global.logging[global.log_level])) {
428 for (i = global.log_level + 1; i < G_N_ELEMENTS (global.logging); i++) {
429 if (diter->num & global.logging[i]) {
430 g_string_append_printf (str, ":%s", global.level_desc[i].name);
436 return g_string_free (str, FALSE);
440 nm_logging_all_domains_to_string (void)
444 if (G_UNLIKELY (!str)) {
445 const LogDesc *diter;
447 str = g_string_new (LOGD_DEFAULT_STRING);
448 for (diter = &global.domain_desc[0]; diter->name; diter++) {
449 g_string_append_c (str, ',');
450 g_string_append (str, diter->name);
451 if (diter->num == LOGD_DHCP6)
452 g_string_append (str, "," LOGD_DHCP_STRING);
453 else if (diter->num == LOGD_IP6)
454 g_string_append (str, "," LOGD_IP_STRING);
456 g_string_append (str, "," LOGD_ALL_STRING);
463 nm_logging_enabled (NMLogLevel level, NMLogDomain domain)
465 if ((guint) level >= G_N_ELEMENTS (global.logging))
466 g_return_val_if_reached (FALSE);
468 /* This function is guaranteed not to modify errno. */
469 _ensure_initialized ();
471 return !!(global.logging[level] & domain);
475 __attribute__((__format__ (__printf__, 4, 5)))
477 _iovec_set_format (struct iovec *iov, gboolean *iov_free, int i, const char *format, ...)
482 va_start (ap, format);
483 str = g_strdup_vprintf (format, ap);
486 iov[i].iov_base = str;
487 iov[i].iov_len = strlen (str);
492 _iovec_set_string (struct iovec *iov, gboolean *iov_free, int i, const char *str, gsize len)
494 iov[i].iov_base = (char *) str;
495 iov[i].iov_len = len;
498 #define _iovec_set_literal_string(iov, iov_free, i, str) _iovec_set_string ((iov), (iov_free), (i), (""str""), NM_STRLEN (str))
502 _nm_log_impl (const char *file,
514 char s_buf_timestamp[64];
515 char s_buf_location[1024];
518 if ((guint) level >= G_N_ELEMENTS (global.logging))
519 g_return_if_reached ();
521 _ensure_initialized ();
523 if (!(global.logging[level] & domain))
526 /* Make sure that %m maps to the specified error */
533 va_start (args, fmt);
534 msg = g_strdup_vprintf (fmt, args);
537 if (NM_FLAGS_ANY (global.log_format_flags, global.level_desc[level].log_format_level & _LOG_FORMAT_FLAG_TIMESTAMP)) {
538 g_get_current_time (&tv);
539 nm_sprintf_buf (s_buf_timestamp, " [%ld.%04ld]", tv.tv_sec, (tv.tv_usec + 50) / 100);
541 s_buf_timestamp[0] = '\0';
543 s_buf_location[0] = '\0';
544 if (NM_FLAGS_ANY (global.log_format_flags, global.level_desc[level].log_format_level & _LOG_FORMAT_FLAG_LOCATION)) {
545 #define MAX_LEN_FILE 37
546 #define MAX_LEN_FUNC 26
547 gsize l = sizeof (s_buf_location);
548 char *p = s_buf_location, *p_buf;
550 char s_buf[MAX (MAX_LEN_FILE, MAX_LEN_FUNC) + 30];
553 if (NM_FLAGS_HAS (global.log_format_flags, LOG_FORMAT_FLAG_ALIGN_LOCATION)) {
554 /* left-align the "[file:line]" string, but truncate from left to MAX_LEN_FILE chars. */
556 nm_sprintf_buf (s_buf, "[%s:%u]",
557 len > MAX_LEN_FILE ? &file[len - MAX_LEN_FILE] : file,
559 len = strlen (s_buf);
560 if (len > MAX_LEN_FILE) {
561 p_buf = &s_buf[len - MAX_LEN_FILE];
565 nm_utils_strbuf_append (&p, &l, " %-"G_STRINGIFY (MAX_LEN_FILE)"s", p_buf);
567 nm_utils_strbuf_append (&p, &l, " [%s:%u]", file, line);
570 if (NM_FLAGS_HAS (global.log_format_flags, LOG_FORMAT_FLAG_ALIGN_LOCATION)) {
571 /* left-align the "func():" string, but truncate from left to MAX_LEN_FUNC chars. */
573 nm_sprintf_buf (s_buf, "%s():",
574 len > MAX_LEN_FUNC ? &func[len - MAX_LEN_FUNC] : func);
575 len = strlen (s_buf);
576 nm_utils_strbuf_append (&p, &l, " %-"G_STRINGIFY (MAX_LEN_FUNC)"s",
577 len > MAX_LEN_FUNC ? &s_buf[len - MAX_LEN_FUNC] : s_buf);
579 nm_utils_strbuf_append (&p, &l, " %s():", func);
583 switch (global.log_backend) {
585 case LOG_BACKEND_JOURNAL:
587 gint64 now, boottime;
588 #define _NUM_MAX_FIELDS_SYSLOG_FACILITY 10
589 #define _NUM_FIELDS (10 + _NUM_MAX_FIELDS_SYSLOG_FACILITY)
591 struct iovec iov[_NUM_FIELDS];
592 gboolean iov_free[_NUM_FIELDS];
594 now = nm_utils_get_monotonic_timestamp_ns ();
595 boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1);
597 _iovec_set_format (iov, iov_free, i_field++, "PRIORITY=%d", global.level_desc[level].syslog_level);
598 _iovec_set_format (iov, iov_free, i_field++, "MESSAGE="
600 global.level_desc[level].level_str,
604 _iovec_set_literal_string (iov, iov_free, i_field++, "SYSLOG_IDENTIFIER=" G_LOG_DOMAIN);
605 _iovec_set_format (iov, iov_free, i_field++, "SYSLOG_PID=%ld", (long) getpid ());
607 const LogDesc *diter;
608 int i_domain = _NUM_MAX_FIELDS_SYSLOG_FACILITY;
609 const char *s_domain_1 = NULL;
610 GString *s_domain_all = NULL;
611 NMLogDomain dom_all = domain;
612 NMLogDomain dom = dom_all & global.logging[level];
614 for (diter = &global.domain_desc[0]; diter->name; diter++) {
615 if (!NM_FLAGS_HAS (dom_all, diter->num))
618 /* construct a list of all domains (not only the enabled ones).
619 * Note that in by far most cases, there is only one domain present.
620 * Hence, save the construction of the GString. */
621 dom_all &= ~diter->num;
623 s_domain_1 = diter->name;
626 s_domain_all = g_string_new (s_domain_1);
627 g_string_append_c (s_domain_all, ',');
628 g_string_append (s_domain_all, diter->name);
631 if (NM_FLAGS_HAS (dom, diter->num)) {
633 /* SYSLOG_FACILITY is specified multiple times for each domain that is actually enabled. */
634 _iovec_set_format (iov, iov_free, i_field++, "SYSLOG_FACILITY=%s", diter->name);
639 if (!dom && !dom_all)
643 _iovec_set_format (iov, iov_free, i_field++, "NM_LOG_DOMAINS=%s", s_domain_all->str);
644 g_string_free (s_domain_all, TRUE);
646 _iovec_set_format (iov, iov_free, i_field++, "NM_LOG_DOMAINS=%s", s_domain_1);
648 _iovec_set_format (iov, iov_free, i_field++, "NM_LOG_LEVEL=%s", global.level_desc[level].name);
649 _iovec_set_format (iov, iov_free, i_field++, "CODE_FUNC=%s", func ?: "");
650 _iovec_set_format (iov, iov_free, i_field++, "CODE_FILE=%s", file ?: "");
651 _iovec_set_format (iov, iov_free, i_field++, "CODE_LINE=%u", line);
652 _iovec_set_format (iov, iov_free, i_field++, "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NS_PER_SECOND), (long long) ((now % NM_UTILS_NS_PER_SECOND) / 1000));
653 _iovec_set_format (iov, iov_free, i_field++, "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NS_PER_SECOND), (long long) ((boottime % NM_UTILS_NS_PER_SECOND) / 1000));
655 _iovec_set_format (iov, iov_free, i_field++, "ERRNO=%d", error);
657 nm_assert (i_field <= G_N_ELEMENTS (iov));
659 sd_journal_sendv (iov, i_field);
661 for (; i_field > 0; ) {
663 if (iov_free[i_field])
664 g_free (iov[i_field].iov_base);
670 fullmsg = g_strdup_printf ("%-7s%s%s %s",
671 global.level_desc[level].level_str,
676 if (global.log_backend == LOG_BACKEND_SYSLOG)
677 syslog (global.level_desc[level].syslog_level, "%s", fullmsg);
679 g_log (G_LOG_DOMAIN, global.level_desc[level].g_log_level, "%s", fullmsg);
687 /************************************************************************/
690 nm_log_handler (const gchar *log_domain,
691 GLogLevelFlags level,
692 const gchar *message,
697 switch (level & G_LOG_LEVEL_MASK) {
698 case G_LOG_LEVEL_ERROR:
699 syslog_priority = LOG_CRIT;
701 case G_LOG_LEVEL_CRITICAL:
702 syslog_priority = LOG_ERR;
704 case G_LOG_LEVEL_WARNING:
705 syslog_priority = LOG_WARNING;
707 case G_LOG_LEVEL_MESSAGE:
708 syslog_priority = LOG_NOTICE;
710 case G_LOG_LEVEL_DEBUG:
711 syslog_priority = LOG_DEBUG;
713 case G_LOG_LEVEL_INFO:
715 syslog_priority = LOG_INFO;
719 switch (global.log_backend) {
721 case LOG_BACKEND_JOURNAL:
723 gint64 now, boottime;
725 now = nm_utils_get_monotonic_timestamp_ns ();
726 boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1);
728 sd_journal_send ("PRIORITY=%d", syslog_priority,
729 "MESSAGE=%s", message ?: "",
730 "SYSLOG_IDENTIFIER=%s", G_LOG_DOMAIN,
731 "SYSLOG_PID=%ld", (long) getpid (),
732 "SYSLOG_FACILITY=GLIB",
733 "GLIB_DOMAIN=%s", log_domain ?: "",
734 "GLIB_LEVEL=%d", (int) (level & G_LOG_LEVEL_MASK),
735 "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NS_PER_SECOND), (long long) ((now % NM_UTILS_NS_PER_SECOND) / 1000),
736 "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NS_PER_SECOND), (long long) ((boottime % NM_UTILS_NS_PER_SECOND) / 1000),
742 syslog (syslog_priority, "%s", message ?: "");
748 nm_logging_syslog_openlog (const char *logging_backend)
750 LogFormatFlags log_format_flags;
752 if (global.log_backend != LOG_BACKEND_GLIB)
753 g_return_if_reached ();
755 if (!logging_backend)
756 logging_backend = ""NM_CONFIG_LOGGING_BACKEND_DEFAULT;
758 log_format_flags = _LOG_FORMAT_FLAG_DEFAULT;
760 if (strcmp (logging_backend, "debug") == 0) {
761 global.log_backend = LOG_BACKEND_SYSLOG;
762 openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
764 } else if (strcmp (logging_backend, "syslog") != 0) {
765 global.log_backend = LOG_BACKEND_JOURNAL;
767 /* ensure we read a monotonic timestamp. Reading the timestamp the first
768 * time causes a logging message. We don't want to do that during _nm_log_impl. */
769 nm_utils_get_monotonic_timestamp_ns ();
772 global.log_backend = LOG_BACKEND_SYSLOG;
773 openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON);
776 global.log_format_flags = log_format_flags;
778 g_log_set_handler (G_LOG_DOMAIN,
779 G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,