logging: add native systemd-journald support to nm-logging
This commit is contained in:
@@ -419,6 +419,7 @@ AM_CPPFLAGS += \
|
|||||||
$(LIBSOUP_CFLAGS) \
|
$(LIBSOUP_CFLAGS) \
|
||||||
$(SELINUX_CFLAGS) \
|
$(SELINUX_CFLAGS) \
|
||||||
$(SYSTEMD_LOGIN_CFLAGS) \
|
$(SYSTEMD_LOGIN_CFLAGS) \
|
||||||
|
$(SYSTEMD_JOURNAL_CFLAGS) \
|
||||||
$(SYSTEMD_NM_CFLAGS) \
|
$(SYSTEMD_NM_CFLAGS) \
|
||||||
\
|
\
|
||||||
-DBINDIR=\"$(bindir)\" \
|
-DBINDIR=\"$(bindir)\" \
|
||||||
@@ -455,6 +456,7 @@ libNetworkManager_la_LIBADD = \
|
|||||||
$(GUDEV_LIBS) \
|
$(GUDEV_LIBS) \
|
||||||
$(LIBNL_LIBS) \
|
$(LIBNL_LIBS) \
|
||||||
$(SYSTEMD_LOGIN_LIBS) \
|
$(SYSTEMD_LOGIN_LIBS) \
|
||||||
|
$(SYSTEMD_JOURNAL_LIBS) \
|
||||||
$(LIBNDP_LIBS) \
|
$(LIBNDP_LIBS) \
|
||||||
$(LIBDL) \
|
$(LIBDL) \
|
||||||
$(LIBM)
|
$(LIBM)
|
||||||
@@ -550,6 +552,7 @@ nm_iface_helper_LDADD = \
|
|||||||
$(DBUS_LIBS) \
|
$(DBUS_LIBS) \
|
||||||
$(GLIB_LIBS) \
|
$(GLIB_LIBS) \
|
||||||
$(GUDEV_LIBS) \
|
$(GUDEV_LIBS) \
|
||||||
|
$(SYSTEMD_JOURNAL_LIBS) \
|
||||||
$(LIBNL_LIBS) \
|
$(LIBNL_LIBS) \
|
||||||
$(LIBNDP_LIBS) \
|
$(LIBNDP_LIBS) \
|
||||||
$(LIBM)
|
$(LIBM)
|
||||||
|
181
src/nm-logging.c
181
src/nm-logging.c
@@ -34,9 +34,16 @@
|
|||||||
|
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#if SYSTEMD_JOURNAL
|
||||||
|
#define SD_JOURNAL_SUPPRESS_LOCATION
|
||||||
|
#include <systemd/sd-journal.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "nm-glib-compat.h"
|
#include "nm-glib-compat.h"
|
||||||
#include "nm-logging.h"
|
#include "nm-logging.h"
|
||||||
#include "nm-errors.h"
|
#include "nm-errors.h"
|
||||||
|
#include "gsystem-local-alloc.h"
|
||||||
|
#include "NetworkManagerUtils.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nm_log_handler (const gchar *log_domain,
|
nm_log_handler (const gchar *log_domain,
|
||||||
@@ -51,6 +58,7 @@ static gboolean logging_set_up;
|
|||||||
enum {
|
enum {
|
||||||
LOG_BACKEND_GLIB,
|
LOG_BACKEND_GLIB,
|
||||||
LOG_BACKEND_SYSLOG,
|
LOG_BACKEND_SYSLOG,
|
||||||
|
LOG_BACKEND_JOURNAL,
|
||||||
} log_backend = LOG_BACKEND_GLIB;
|
} log_backend = LOG_BACKEND_GLIB;
|
||||||
static char *logging_domains_to_string;
|
static char *logging_domains_to_string;
|
||||||
|
|
||||||
@@ -363,6 +371,33 @@ nm_logging_enabled (NMLogLevel level, NMLogDomain domain)
|
|||||||
return !!(logging[level] & domain);
|
return !!(logging[level] & domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SYSTEMD_JOURNAL
|
||||||
|
__attribute__((__format__ (__printf__, 4, 5)))
|
||||||
|
static void
|
||||||
|
_iovec_set_format (struct iovec *iov, gboolean *iov_free, int i, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
va_start (ap, format);
|
||||||
|
str = g_strdup_vprintf (format, ap);
|
||||||
|
va_end (ap);
|
||||||
|
|
||||||
|
iov[i].iov_base = str;
|
||||||
|
iov[i].iov_len = strlen (str);
|
||||||
|
iov_free[i] = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_iovec_set_string (struct iovec *iov, gboolean *iov_free, int i, const char *str, gsize len)
|
||||||
|
{
|
||||||
|
iov[i].iov_base = (char *) str;
|
||||||
|
iov[i].iov_len = len;
|
||||||
|
iov_free[i] = FALSE;
|
||||||
|
}
|
||||||
|
#define _iovec_set_literal_string(iov, iov_free, i, str) _iovec_set_string ((iov), (iov_free), (i), (""str""), STRLEN (str))
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
_nm_log_impl (const char *file,
|
_nm_log_impl (const char *file,
|
||||||
guint line,
|
guint line,
|
||||||
@@ -382,7 +417,8 @@ _nm_log_impl (const char *file,
|
|||||||
gboolean full_details = FALSE;
|
gboolean full_details = FALSE;
|
||||||
const char *level_str = NULL;
|
const char *level_str = NULL;
|
||||||
|
|
||||||
g_return_if_fail (level < LOGL_MAX);
|
if ((guint) level >= LOGL_MAX)
|
||||||
|
g_return_if_reached ();
|
||||||
|
|
||||||
_ensure_initialized ();
|
_ensure_initialized ();
|
||||||
|
|
||||||
@@ -431,18 +467,99 @@ _nm_log_impl (const char *file,
|
|||||||
g_return_if_reached ();
|
g_return_if_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (full_details) {
|
|
||||||
g_get_current_time (&tv);
|
|
||||||
fullmsg = g_strdup_printf ("%-7s [%ld.%06ld] [%s:%u] %s(): %s", level_str, tv.tv_sec, tv.tv_usec, file, line, func, msg);
|
|
||||||
} else
|
|
||||||
fullmsg = g_strdup_printf ("%-7s %s", level_str, msg);
|
|
||||||
|
|
||||||
switch (log_backend) {
|
switch (log_backend) {
|
||||||
case LOG_BACKEND_SYSLOG:
|
#if SYSTEMD_JOURNAL
|
||||||
syslog (syslog_level, "%s", fullmsg);
|
case LOG_BACKEND_JOURNAL:
|
||||||
|
{
|
||||||
|
gint64 now, boottime;
|
||||||
|
#define _NUM_MAX_FIELDS_SYSLOG_FACILITY 10
|
||||||
|
#define _NUM_FIELDS (10 + _NUM_MAX_FIELDS_SYSLOG_FACILITY)
|
||||||
|
int i_field = 0;
|
||||||
|
struct iovec iov[_NUM_FIELDS];
|
||||||
|
gboolean iov_free[_NUM_FIELDS];
|
||||||
|
|
||||||
|
now = nm_utils_get_monotonic_timestamp_ns ();
|
||||||
|
boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1);
|
||||||
|
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "PRIORITY=%d", syslog_level);
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "MESSAGE=%-7s %s", level_str, msg);
|
||||||
|
_iovec_set_literal_string (iov, iov_free, i_field++, "SYSLOG_IDENTIFIER=" G_LOG_DOMAIN);
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "SYSLOG_PID=%ld", (long) getpid ());
|
||||||
|
{
|
||||||
|
const LogDesc *diter;
|
||||||
|
int i_domain = _NUM_MAX_FIELDS_SYSLOG_FACILITY;
|
||||||
|
const char *s_domain_1 = NULL;
|
||||||
|
GString *s_domain_all = NULL;
|
||||||
|
NMLogDomain dom_all = domain;
|
||||||
|
NMLogDomain dom = dom_all & logging[level];
|
||||||
|
|
||||||
|
for (diter = &domain_descs[0]; diter->name; diter++) {
|
||||||
|
if (!NM_FLAGS_HAS (dom_all, diter->num))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* construct a list of all domains (not only the enabled ones).
|
||||||
|
* Note that in by far most cases, there is only one domain present.
|
||||||
|
* Hence, save the construction of the GString. */
|
||||||
|
dom_all &= ~diter->num;
|
||||||
|
if (!s_domain_1)
|
||||||
|
s_domain_1 = diter->name;
|
||||||
|
else {
|
||||||
|
if (!s_domain_all)
|
||||||
|
s_domain_all = g_string_new (s_domain_1);
|
||||||
|
g_string_append_c (s_domain_all, ',');
|
||||||
|
g_string_append (s_domain_all, diter->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NM_FLAGS_HAS (dom, diter->num)) {
|
||||||
|
if (i_domain > 0) {
|
||||||
|
/* SYSLOG_FACILITY is specified multiple times for each domain that is actually enabled. */
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "SYSLOG_FACILITY=%s", diter->name);
|
||||||
|
i_domain--;
|
||||||
|
}
|
||||||
|
dom &= ~diter->num;
|
||||||
|
}
|
||||||
|
if (!dom && !dom_all)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (s_domain_all) {
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "NM_LOG_DOMAINS=%s", s_domain_all->str);
|
||||||
|
g_string_free (s_domain_all, TRUE);
|
||||||
|
} else
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "NM_LOG_DOMAINS=%s", s_domain_1);
|
||||||
|
}
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "NM_LOG_LEVEL=%s", level_names[level]);
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "CODE_FUNC=%s", func);
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "CODE_FILE=%s", file);
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "CODE_LINE=%u", line);
|
||||||
|
_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));
|
||||||
|
_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));
|
||||||
|
if (error != 0)
|
||||||
|
_iovec_set_format (iov, iov_free, i_field++, "ERRNO=%d", error);
|
||||||
|
|
||||||
|
nm_assert (i_field <= G_N_ELEMENTS (iov));
|
||||||
|
|
||||||
|
sd_journal_sendv (iov, i_field);
|
||||||
|
|
||||||
|
for (; i_field > 0; ) {
|
||||||
|
i_field--;
|
||||||
|
if (iov_free[i_field])
|
||||||
|
g_free (iov[i_field].iov_base);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
g_log (G_LOG_DOMAIN, g_log_level, "%s", fullmsg);
|
if (full_details) {
|
||||||
|
g_get_current_time (&tv);
|
||||||
|
fullmsg = g_strdup_printf ("%-7s [%ld.%06ld] [%s:%u] %s(): %s", level_str, tv.tv_sec, tv.tv_usec, file, line, func, msg);
|
||||||
|
} else
|
||||||
|
fullmsg = g_strdup_printf ("%-7s %s", level_str, msg);
|
||||||
|
|
||||||
|
if (log_backend == LOG_BACKEND_SYSLOG)
|
||||||
|
syslog (syslog_level, "%s", fullmsg);
|
||||||
|
else
|
||||||
|
g_log (G_LOG_DOMAIN, g_log_level, "%s", fullmsg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (msg);
|
g_free (msg);
|
||||||
@@ -481,7 +598,32 @@ nm_log_handler (const gchar *log_domain,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
syslog (syslog_priority, "%s", message);
|
switch (log_backend) {
|
||||||
|
#if SYSTEMD_JOURNAL
|
||||||
|
case LOG_BACKEND_JOURNAL:
|
||||||
|
{
|
||||||
|
gint64 now, boottime;
|
||||||
|
|
||||||
|
now = nm_utils_get_monotonic_timestamp_ns ();
|
||||||
|
boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1);
|
||||||
|
|
||||||
|
sd_journal_send ("PRIORITY=%d", syslog_priority,
|
||||||
|
"MESSAGE=%s", str_if_set (message, ""),
|
||||||
|
"SYSLOG_IDENTIFIER=%s", G_LOG_DOMAIN,
|
||||||
|
"SYSLOG_PID=%ld", (long) getpid (),
|
||||||
|
"SYSLOG_FACILITY=GLIB",
|
||||||
|
"GLIB_DOMAIN=%s", str_if_set (log_domain, ""),
|
||||||
|
"GLIB_LEVEL=%d", (int) (level & G_LOG_LEVEL_MASK),
|
||||||
|
"TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NS_PER_SECOND), (long long) ((now % NM_UTILS_NS_PER_SECOND) / 1000),
|
||||||
|
"TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NS_PER_SECOND), (long long) ((boottime % NM_UTILS_NS_PER_SECOND) / 1000),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
syslog (syslog_priority, "%s", str_if_set (message, ""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -490,12 +632,21 @@ nm_logging_syslog_openlog (gboolean debug)
|
|||||||
if (log_backend != LOG_BACKEND_GLIB)
|
if (log_backend != LOG_BACKEND_GLIB)
|
||||||
g_return_if_reached ();
|
g_return_if_reached ();
|
||||||
|
|
||||||
log_backend = LOG_BACKEND_SYSLOG;
|
if (debug) {
|
||||||
|
log_backend = LOG_BACKEND_SYSLOG;
|
||||||
if (debug)
|
|
||||||
openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
|
openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
|
||||||
else
|
#if SYSTEMD_JOURNAL
|
||||||
|
} else if (TRUE) {
|
||||||
|
log_backend = LOG_BACKEND_JOURNAL;
|
||||||
|
|
||||||
|
/* ensure we read a monotonic timestamp. Reading the timestamp the first
|
||||||
|
* time causes a logging message. We don't want to do that during _nm_log_impl. */
|
||||||
|
nm_utils_get_monotonic_timestamp_ns ();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
log_backend = LOG_BACKEND_SYSLOG;
|
||||||
openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON);
|
openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON);
|
||||||
|
}
|
||||||
|
|
||||||
g_log_set_handler (G_LOG_DOMAIN,
|
g_log_set_handler (G_LOG_DOMAIN,
|
||||||
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
|
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
|
||||||
|
Reference in New Issue
Block a user