summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-07-14 15:59:13 +0200
committerThomas Haller <thaller@redhat.com>2015-07-14 15:59:13 +0200
commit59ca132b3aafd7cabcdfe045ac966279c96a92b2 (patch)
tree91ef2a673c02c5832a47d077fe18f2a4d7dc35b6
parent5cc2eabe5d24c8d9fe30aa675d48c7fa121d7c93 (diff)
parent81f3c36f231c34132a542aaf37c0ffd7ee30baaf (diff)
downloadNetworkManager-59ca132b3aafd7cabcdfe045ac966279c96a92b2.tar.gz
logging: merge branch 'th/logging-sd-journal-bgo752136'
https://bugzilla.gnome.org/show_bug.cgi?id=752136
-rw-r--r--configure.ac45
-rw-r--r--man/NetworkManager.conf.xml.in14
-rw-r--r--src/Makefile.am3
-rw-r--r--src/devices/nm-device.c12
-rw-r--r--src/main.c13
-rw-r--r--src/nm-config-data.c21
-rw-r--r--src/nm-config-data.h1
-rw-r--r--src/nm-config.c10
-rw-r--r--src/nm-config.h2
-rw-r--r--src/nm-iface-helper.c8
-rw-r--r--src/nm-logging.c282
-rw-r--r--src/nm-logging.h3
12 files changed, 334 insertions, 80 deletions
diff --git a/configure.ac b/configure.ac
index c31f27f350..9d5ad54719 100644
--- a/configure.ac
+++ b/configure.ac
@@ -376,6 +376,50 @@ elif test "$hostname_persist" = gentoo; then
AC_DEFINE(HOSTNAME_PERSIST_GENTOO, 1, [Enable Gentoo hostname persist method])
fi
+AC_ARG_WITH(systemd-journal, AS_HELP_STRING([--with-systemd-journal=yes|no], [Use systemd journal for logging]))
+have_systemd_journal=no
+if test "$with_systemd_journal" != "no"; then
+ PKG_CHECK_MODULES(SYSTEMD_JOURNAL,
+ [libsystemd >= 209],
+ [have_systemd_journal=yes],
+ [PKG_CHECK_MODULES(SYSTEMD_JOURNAL,
+ [libsystemd-journal],
+ [have_systemd_journal=yes],
+ [have_systemd_journal=no])])
+ if test "$have_systemd_journal" != "yes"; then
+ if test "$with_systemd_journal" = "yes"; then
+ AC_MSG_ERROR([Missing systemd-journald support])
+ fi
+ fi
+fi
+if test "$have_systemd_journal" = "yes"; then
+ AC_SUBST(SYSTEMD_JOURNAL_CFLAGS)
+ AC_SUBST(SYSTEMD_JOURNAL_LIBS)
+ AC_DEFINE([SYSTEMD_JOURNAL], 1, [Define to 1 if libsystemd-journald is available])
+else
+ AC_DEFINE([SYSTEMD_JOURNAL], 0, [Define to 1 if libsystemd-journald is available])
+fi
+
+AC_ARG_WITH(config-logging-backend-default, AS_HELP_STRING([--with-logging-backend-default=backend], [Default value for logging.backend]), nm_config_logging_backend_default="$withval", nm_config_logging_backend_default="")
+if test "$nm_config_logging_backend_default" != 'debug' \
+ -a "$nm_config_logging_backend_default" != 'syslog' \
+ -a "$nm_config_logging_backend_default" != 'journal' \
+ -a "$nm_config_logging_backend_default" != 'journal-syslog-style'; then
+ # unknown backend. Reset to default. Silently accept the invalid value to
+ # be future proof.
+ nm_config_logging_backend_default=''
+fi
+if test "$nm_config_logging_backend_default" = ""; then
+ if test "$have_systemd_journal" = "yes"; then
+ nm_config_logging_backend_default='journal-syslog-style'
+ else
+ nm_config_logging_backend_default='syslog'
+ fi
+fi
+AC_DEFINE_UNQUOTED(NM_CONFIG_LOGGING_BACKEND_DEFAULT, "$nm_config_logging_backend_default", [Default configuration option for logging.backend])
+NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT="$nm_config_logging_backend_default"
+AC_SUBST(NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT)
+
# Session tracking support
AC_ARG_WITH(systemd-logind, AS_HELP_STRING([--with-systemd-logind=yes|no],
[Support systemd session tracking]))
@@ -1091,6 +1135,7 @@ else
fi
echo " polkit agent: ${enable_polkit_agent}"
echo " selinux: $have_selinux"
+echo " systemd-journald: $have_systemd_journal (logging.backend: ${nm_config_logging_backend_default})"
echo " hostname persist: ${hostname_persist}"
echo
diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in
index bf15c9e8b5..4d4c8a293f 100644
--- a/man/NetworkManager.conf.xml.in
+++ b/man/NetworkManager.conf.xml.in
@@ -470,6 +470,20 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
</simplelist>
</para>
</varlistentry>
+ <varlistentry>
+ <term><varname>backend</varname></term>
+ <listitem><para>The logging backend. Supported values
+ are "<literal>debug</literal>", "<literal>syslog</literal>",
+ "<literal>journal</literal>" and "<literal>journal-syslog-style</literal>.
+ "<literal>debug</literal>" uses syslog and logs to standard error.
+ "<literal>journal-syslog-style</literal>" prints the same message to journal
+ as it would print for "<literal>syslog</literal>", containing redudant
+ fields in the text.
+ If NetworkManager is started in debug mode (<literal>--debug</literal>)
+ this option is ignored and "<literal>debug</literal>" is always used.
+ Otherwise, the default is "<literal>@NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@</literal>".
+ </para></listitem>
+ </varlistentry>
</variablelist>
</para>
</refsect1>
diff --git a/src/Makefile.am b/src/Makefile.am
index 69ec19b9d3..cc0a0aecd1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -419,6 +419,7 @@ AM_CPPFLAGS += \
$(LIBSOUP_CFLAGS) \
$(SELINUX_CFLAGS) \
$(SYSTEMD_LOGIN_CFLAGS) \
+ $(SYSTEMD_JOURNAL_CFLAGS) \
$(SYSTEMD_NM_CFLAGS) \
\
-DBINDIR=\"$(bindir)\" \
@@ -455,6 +456,7 @@ libNetworkManager_la_LIBADD = \
$(GUDEV_LIBS) \
$(LIBNL_LIBS) \
$(SYSTEMD_LOGIN_LIBS) \
+ $(SYSTEMD_JOURNAL_LIBS) \
$(LIBNDP_LIBS) \
$(LIBDL) \
$(LIBM)
@@ -550,6 +552,7 @@ nm_iface_helper_LDADD = \
$(DBUS_LIBS) \
$(GLIB_LIBS) \
$(GUDEV_LIBS) \
+ $(SYSTEMD_JOURNAL_LIBS) \
$(LIBNL_LIBS) \
$(LIBNDP_LIBS) \
$(LIBM)
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 415465ada2..913c48840b 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -8092,6 +8092,7 @@ nm_device_spawn_iface_helper (NMDevice *self)
const char *method;
GPtrArray *argv;
gs_free char *dhcp4_address = NULL;
+ char *logging_backend;
if (priv->state != NM_DEVICE_STATE_ACTIVATED)
return;
@@ -8110,6 +8111,17 @@ nm_device_spawn_iface_helper (NMDevice *self)
g_ptr_array_add (argv, g_strdup ("--uuid"));
g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection)));
+ logging_backend = nm_config_get_is_debug (nm_config_get ())
+ ? g_strdup ("debug")
+ : nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG,
+ NM_CONFIG_KEYFILE_GROUP_LOGGING,
+ NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND,
+ NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
+ if (logging_backend) {
+ g_ptr_array_add (argv, g_strdup ("--logging-backend"));
+ g_ptr_array_add (argv, logging_backend);
+ }
+
dhcp4_address = find_dhcp4_address (self);
method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG);
diff --git a/src/main.c b/src/main.c
index 65ba7a61d7..27babf81ec 100644
--- a/src/main.c
+++ b/src/main.c
@@ -70,7 +70,6 @@ static gboolean configure_and_quit = FALSE;
static struct {
gboolean show_version;
gboolean become_daemon;
- gboolean debug;
gboolean g_fatal_warnings;
gboolean run_from_build_dir;
char *opt_log_level;
@@ -231,7 +230,6 @@ do_early_setup (int *argc, char **argv[], NMConfigCmdLineOptions *config_cli)
GOptionEntry options[] = {
{ "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL },
{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.become_daemon, N_("Don't become a daemon"), NULL },
- { "debug", 'd', 0, G_OPTION_ARG_NONE, &global_opt.debug, N_("Don't become a daemon, and log to stderr"), NULL },
{ "log-level", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_level, N_("Log level: one of [%s]"), "INFO" },
{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_domains,
N_("Log domains separated by ',': any combination of [%s]"),
@@ -372,7 +370,7 @@ main (int argc, char *argv[])
}
}
- if (global_opt.become_daemon && !global_opt.debug) {
+ if (global_opt.become_daemon && !nm_config_get_is_debug (config)) {
if (daemon (0, 0) < 0) {
int saved_errno;
@@ -388,7 +386,12 @@ main (int argc, char *argv[])
/* Set up unix signal handling - before creating threads, but after daemonizing! */
nm_main_utils_setup_signals (main_loop);
- nm_logging_syslog_openlog (global_opt.debug);
+ nm_logging_syslog_openlog (nm_config_get_is_debug (config)
+ ? "debug"
+ : nm_config_data_get_value_cached (NM_CONFIG_GET_DATA_ORIG,
+ NM_CONFIG_KEYFILE_GROUP_LOGGING,
+ NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND,
+ NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY));
nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");
@@ -488,8 +491,6 @@ main (int argc, char *argv[])
done:
g_clear_object (&manager);
- nm_logging_syslog_closelog ();
-
if (global_opt.pidfile && wrote_pidfile)
unlink (global_opt.pidfile);
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
index 03cae638c7..5e015f016e 100644
--- a/src/nm-config-data.c
+++ b/src/nm-config-data.c
@@ -72,6 +72,9 @@ typedef struct {
char *dns_mode;
char *rc_manager;
+
+ /* mutable field */
+ char *value_cached;
} NMConfigDataPrivate;
@@ -138,6 +141,22 @@ nm_config_data_get_value (const NMConfigData *self, const char *group, const cha
return nm_config_keyfile_get_value (NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile, group, key, flags);
}
+const char *nm_config_data_get_value_cached (const NMConfigData *self, const char *group, const char *key, NMConfigGetValueFlags flags)
+{
+ NMConfigDataPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_CONFIG_DATA (self), NULL);
+ g_return_val_if_fail (group && *group, NULL);
+ g_return_val_if_fail (key && *key, NULL);
+
+ priv = NM_CONFIG_DATA_GET_PRIVATE (self);
+
+ /* we modify @value_cached. In C++ jargon, the field is mutable. */
+ g_free (priv->value_cached);
+ priv->value_cached = nm_config_keyfile_get_value (priv->keyfile, group, key, flags);
+ return priv->value_cached;
+}
+
gboolean
nm_config_data_has_value (const NMConfigData *self, const char *group, const char *key, NMConfigGetValueFlags flags)
{
@@ -801,6 +820,8 @@ finalize (GObject *gobject)
g_key_file_unref (priv->keyfile_intern);
G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject);
+
+ g_free (priv->value_cached);
}
static void
diff --git a/src/nm-config-data.h b/src/nm-config-data.h
index 0dfdf531ec..36aa66af95 100644
--- a/src/nm-config-data.h
+++ b/src/nm-config-data.h
@@ -111,6 +111,7 @@ const char *nm_config_data_get_config_description (const NMConfigData *config_da
gboolean nm_config_data_has_group (const NMConfigData *self, const char *group);
gboolean nm_config_data_has_value (const NMConfigData *self, const char *group, const char *key, NMConfigGetValueFlags flags);
char *nm_config_data_get_value (const NMConfigData *config_data, const char *group, const char *key, NMConfigGetValueFlags flags);
+const char *nm_config_data_get_value_cached (const NMConfigData *config_data, const char *group, const char *key, NMConfigGetValueFlags flags);
gint nm_config_data_get_value_boolean (const NMConfigData *self, const char *group, const char *key, gint default_value);
const char *nm_config_data_get_connectivity_uri (const NMConfigData *config_data);
diff --git a/src/nm-config.c b/src/nm-config.c
index 07ea26980e..3490959a7c 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -53,6 +53,7 @@ struct NMConfigCmdLineOptions {
char *no_auto_default_file;
char *plugins;
gboolean configure_and_quit;
+ gboolean is_debug;
char *connectivity_uri;
/* We store interval as signed internally to track whether it's
@@ -318,6 +319,12 @@ nm_config_get_configure_and_quit (NMConfig *config)
return NM_CONFIG_GET_PRIVATE (config)->configure_and_quit;
}
+gboolean
+nm_config_get_is_debug (NMConfig *config)
+{
+ return NM_CONFIG_GET_PRIVATE (config)->cli.is_debug;
+}
+
/************************************************************************/
static char **
@@ -432,6 +439,7 @@ _nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli)
g_clear_pointer (&cli->intern_config_file, g_free);
g_clear_pointer (&cli->plugins, g_free);
cli->configure_and_quit = FALSE;
+ cli->is_debug = FALSE;
g_clear_pointer (&cli->connectivity_uri, g_free);
g_clear_pointer (&cli->connectivity_response, g_free);
cli->connectivity_interval = -1;
@@ -452,6 +460,7 @@ _nm_config_cmd_line_options_copy (const NMConfigCmdLineOptions *cli, NMConfigCmd
dst->intern_config_file = g_strdup (cli->intern_config_file);
dst->plugins = g_strdup (cli->plugins);
dst->configure_and_quit = cli->configure_and_quit;
+ dst->is_debug = cli->is_debug;
dst->connectivity_uri = g_strdup (cli->connectivity_uri);
dst->connectivity_response = g_strdup (cli->connectivity_response);
dst->connectivity_interval = cli->connectivity_interval;
@@ -491,6 +500,7 @@ nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli,
{ "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, N_("State file for no-auto-default devices"), N_(DEFAULT_NO_AUTO_DEFAULT_FILE) },
{ "plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), N_(CONFIG_PLUGINS_DEFAULT) },
{ "configure-and-quit", 0, 0, G_OPTION_ARG_NONE, &cli->configure_and_quit, N_("Quit after initial configuration"), NULL },
+ { "debug", 'd', 0, G_OPTION_ARG_NONE, &cli->is_debug, N_("Don't become a daemon, and log to stderr"), NULL },
/* These three are hidden for now, and should eventually just go away. */
{ "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" },
diff --git a/src/nm-config.h b/src/nm-config.h
index 3caf0c5c31..870d4e4fe5 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -61,6 +61,7 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_GROUP_IFUPDOWN "ifupdown"
#define NM_CONFIG_KEYFILE_GROUP_IFNET "ifnet"
+#define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND "backend"
#define NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS ".was"
#define NM_CONFIG_KEYFILE_KEY_IFNET_AUTO_REFRESH "auto_refresh"
#define NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED "managed"
@@ -102,6 +103,7 @@ const char *nm_config_get_log_level (NMConfig *config);
const char *nm_config_get_log_domains (NMConfig *config);
const char *nm_config_get_debug (NMConfig *config);
gboolean nm_config_get_configure_and_quit (NMConfig *config);
+gboolean nm_config_get_is_debug (NMConfig *config);
void nm_config_set_values (NMConfig *self,
GKeyFile *keyfile_intern_new,
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index cbff221a85..bec6cc8359 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -72,6 +72,7 @@ static struct {
char *dhcp4_clientid;
char *dhcp4_hostname;
char *iid_str;
+ char *logging_backend;
char *opt_log_level;
char *opt_log_domains;
guint32 priority_v4;
@@ -294,6 +295,7 @@ do_early_setup (int *argc, char **argv[])
{ "priority4", '\0', 0, G_OPTION_ARG_INT64, &priority64_v4, N_("Route priority for IPv4"), N_("0") },
{ "priority6", '\0', 0, G_OPTION_ARG_INT64, &priority64_v6, N_("Route priority for IPv6"), N_("1024") },
{ "iid", 'e', 0, G_OPTION_ARG_STRING, &global_opt.iid_str, N_("Hex-encoded Interface Identifier"), "" },
+ { "logging-backend", '\0', 0, G_OPTION_ARG_STRING, &global_opt.logging_backend, N_("The logging backend configuration value. See logging.backend in NetworkManager.conf"), NULL },
/* Logging/debugging */
{ "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL },
@@ -405,7 +407,9 @@ main (int argc, char *argv[])
main_loop = g_main_loop_new (NULL, FALSE);
setup_signals ();
- nm_logging_syslog_openlog (global_opt.debug);
+ nm_logging_syslog_openlog (global_opt.logging_backend
+ ? global_opt.logging_backend
+ : (global_opt.debug ? "debug" : NULL));
nm_log_info (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting...");
@@ -481,8 +485,6 @@ main (int argc, char *argv[])
g_clear_pointer (&hwaddr, g_byte_array_unref);
- nm_logging_syslog_closelog ();
-
if (pidfile && wrote_pidfile)
unlink (pidfile);
diff --git a/src/nm-logging.c b/src/nm-logging.c
index d8dc4291ac..eed89dec06 100644
--- a/src/nm-logging.c
+++ b/src/nm-logging.c
@@ -34,9 +34,16 @@
#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-logging.h"
#include "nm-errors.h"
+#include "gsystem-local-alloc.h"
+#include "NetworkManagerUtils.h"
static void
nm_log_handler (const gchar *log_domain,
@@ -48,7 +55,12 @@ static NMLogLevel log_level = LOGL_INFO;
static char *log_domains;
static NMLogDomain logging[LOGL_MAX];
static gboolean logging_set_up;
-static gboolean syslog_opened;
+enum {
+ LOG_BACKEND_GLIB,
+ LOG_BACKEND_SYSLOG,
+ LOG_BACKEND_JOURNAL,
+ LOG_BACKEND_JOURNAL_SYSLOG_STYLE,
+} log_backend = LOG_BACKEND_GLIB;
static char *logging_domains_to_string;
typedef struct {
@@ -56,12 +68,20 @@ typedef struct {
const char *name;
} LogDesc;
-static const char *level_names[LOGL_MAX] = {
- [LOGL_TRACE] = "TRACE",
- [LOGL_DEBUG] = "DEBUG",
- [LOGL_INFO] = "INFO",
- [LOGL_WARN] = "WARN",
- [LOGL_ERR] = "ERR",
+typedef struct {
+ const char *name;
+ const char *level_str;
+ int syslog_level;
+ GLogLevelFlags g_log_level;
+ gboolean full_details;
+} LogLevelDesc;
+
+static const LogLevelDesc level_desc[LOGL_MAX] = {
+ [LOGL_TRACE] = { "TRACE", "<trace>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, TRUE },
+ [LOGL_DEBUG] = { "DEBUG", "<debug>", LOG_INFO, G_LOG_LEVEL_DEBUG, TRUE },
+ [LOGL_INFO] = { "INFO", "<info>", LOG_INFO, G_LOG_LEVEL_MESSAGE, FALSE },
+ [LOGL_WARN] = { "WARN", "<warn>", LOG_WARNING, G_LOG_LEVEL_WARNING, FALSE },
+ [LOGL_ERR] = { "ERR", "<error>", LOG_ERR, G_LOG_LEVEL_WARNING, TRUE },
};
static const LogDesc domain_descs[] = {
@@ -129,7 +149,7 @@ match_log_level (const char *level,
int i;
for (i = 0; i < LOGL_MAX; i++) {
- if (!g_ascii_strcasecmp (level_names[i], level)) {
+ if (!g_ascii_strcasecmp (level_desc[i].name, level)) {
*out_level = i;
return TRUE;
}
@@ -259,7 +279,7 @@ nm_logging_setup (const char *level,
const char *
nm_logging_level_to_string (void)
{
- return level_names[log_level];
+ return level_desc[log_level].name;
}
const char *
@@ -274,7 +294,7 @@ nm_logging_all_levels_to_string (void)
for (i = 0; i < LOGL_MAX; i++) {
if (str->len)
g_string_append_c (str, ',');
- g_string_append (str, level_names[i]);
+ g_string_append (str, level_desc[i].name);
}
}
@@ -308,7 +328,7 @@ nm_logging_domains_to_string (void)
/* Check if it's logging at a lower level than the default. */
for (i = 0; i < log_level; i++) {
if (diter->num & logging[i]) {
- g_string_append_printf (str, ":%s", level_names[i]);
+ g_string_append_printf (str, ":%s", level_desc[i].name);
break;
}
}
@@ -316,7 +336,7 @@ nm_logging_domains_to_string (void)
if (!(diter->num & logging[log_level])) {
for (i = log_level + 1; i < LOGL_MAX; i++) {
if (diter->num & logging[i]) {
- g_string_append_printf (str, ":%s", level_names[i]);
+ g_string_append_printf (str, ":%s", level_desc[i].name);
break;
}
}
@@ -360,6 +380,33 @@ nm_logging_enabled (NMLogLevel level, NMLogDomain 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
_nm_log_impl (const char *file,
guint line,
@@ -374,10 +421,9 @@ _nm_log_impl (const char *file,
char *msg;
char *fullmsg = NULL;
GTimeVal tv;
- int syslog_level = LOG_INFO;
- int g_log_level = G_LOG_LEVEL_INFO;
- g_return_if_fail (level < LOGL_MAX);
+ if ((guint) level >= LOGL_MAX)
+ g_return_if_reached ();
_ensure_initialized ();
@@ -392,44 +438,106 @@ _nm_log_impl (const char *file,
msg = g_strdup_vprintf (fmt, args);
va_end (args);
- switch (level) {
- case LOGL_TRACE:
- g_get_current_time (&tv);
- syslog_level = LOG_DEBUG;
- g_log_level = G_LOG_LEVEL_DEBUG;
- fullmsg = g_strdup_printf ("<trace> [%ld.%06ld] [%s:%u] %s(): %s", tv.tv_sec, tv.tv_usec, file, line, func, msg);
- break;
- case LOGL_DEBUG:
- g_get_current_time (&tv);
- syslog_level = LOG_INFO;
- g_log_level = G_LOG_LEVEL_DEBUG;
- fullmsg = g_strdup_printf ("<debug> [%ld.%06ld] [%s:%u] %s(): %s", tv.tv_sec, tv.tv_usec, file, line, func, msg);
- break;
- case LOGL_INFO:
- syslog_level = LOG_INFO;
- g_log_level = G_LOG_LEVEL_MESSAGE;
- fullmsg = g_strconcat ("<info> ", msg, NULL);
- break;
- case LOGL_WARN:
- syslog_level = LOG_WARNING;
- g_log_level = G_LOG_LEVEL_WARNING;
- fullmsg = g_strconcat ("<warn> ", msg, NULL);
- break;
- case LOGL_ERR:
- syslog_level = LOG_ERR;
- /* g_log_level is still WARNING, because ERROR is fatal */
- g_log_level = G_LOG_LEVEL_WARNING;
- g_get_current_time (&tv);
- fullmsg = g_strdup_printf ("<error> [%ld.%06ld] [%s:%u] %s(): %s", tv.tv_sec, tv.tv_usec, file, line, func, msg);
+ switch (log_backend) {
+#if SYSTEMD_JOURNAL
+ case LOG_BACKEND_JOURNAL:
+ case LOG_BACKEND_JOURNAL_SYSLOG_STYLE:
+ {
+ 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", level_desc[level].syslog_level);
+ if ( log_backend == LOG_BACKEND_JOURNAL_SYSLOG_STYLE
+ && level_desc[level].full_details) {
+ g_get_current_time (&tv);
+ _iovec_set_format (iov, iov_free, i_field++, "MESSAGE=%-7s [%ld.%06ld] [%s:%u] %s(): %s", level_desc[level].level_str, tv.tv_sec, tv.tv_usec, file, line, func, msg);
+ } else
+ _iovec_set_format (iov, iov_free, i_field++, "MESSAGE=%-7s %s", level_desc[level].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_desc[level].name);
+ _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;
+#endif
default:
- g_assert_not_reached ();
- }
+ if (level_desc[level].full_details) {
+ g_get_current_time (&tv);
+ fullmsg = g_strdup_printf ("%-7s [%ld.%06ld] [%s:%u] %s(): %s", level_desc[level].level_str, tv.tv_sec, tv.tv_usec, file, line, func, msg);
+ } else
+ fullmsg = g_strdup_printf ("%-7s %s", level_desc[level].level_str, msg);
- if (syslog_opened)
- syslog (syslog_level, "%s", fullmsg);
- else
- g_log (G_LOG_DOMAIN, g_log_level, "%s", fullmsg);
+ if (log_backend == LOG_BACKEND_SYSLOG)
+ syslog (level_desc[level].syslog_level, "%s", fullmsg);
+ else
+ g_log (G_LOG_DOMAIN, level_desc[level].g_log_level, "%s", fullmsg);
+ break;
+ }
g_free (msg);
g_free (fullmsg);
@@ -443,7 +551,7 @@ nm_log_handler (const gchar *log_domain,
const gchar *message,
gpointer ignored)
{
- int syslog_priority;
+ int syslog_priority;
switch (level & G_LOG_LEVEL_MASK) {
case G_LOG_LEVEL_ERROR:
@@ -467,30 +575,66 @@ nm_log_handler (const gchar *log_domain,
break;
}
- syslog (syslog_priority, "%s", message);
+ switch (log_backend) {
+#if SYSTEMD_JOURNAL
+ case LOG_BACKEND_JOURNAL:
+ case LOG_BACKEND_JOURNAL_SYSLOG_STYLE:
+ {
+ 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
-nm_logging_syslog_openlog (gboolean debug)
+nm_logging_syslog_openlog (const char *logging_backend)
{
- if (debug)
- openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
- else
- openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON);
+ if (log_backend != LOG_BACKEND_GLIB)
+ g_return_if_reached ();
- if (!syslog_opened) {
- syslog_opened = TRUE;
+ if (!logging_backend)
+ logging_backend = ""NM_CONFIG_LOGGING_BACKEND_DEFAULT;
- g_log_set_handler (G_LOG_DOMAIN,
- G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
- nm_log_handler,
- NULL);
+ if (strcmp (logging_backend, "debug") == 0) {
+ log_backend = LOG_BACKEND_SYSLOG;
+ openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
+#if SYSTEMD_JOURNAL
+ } else if (strcmp (logging_backend, "syslog") != 0) {
+ if (strcmp (logging_backend, "journal-syslog-style") != 0)
+ log_backend = LOG_BACKEND_JOURNAL;
+ else
+ log_backend = LOG_BACKEND_JOURNAL_SYSLOG_STYLE;
+
+ /* 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);
}
-}
-void
-nm_logging_syslog_closelog (void)
-{
- if (syslog_opened)
- closelog ();
+ g_log_set_handler (G_LOG_DOMAIN,
+ G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
+ nm_log_handler,
+ NULL);
}
+
diff --git a/src/nm-logging.h b/src/nm-logging.h
index d02e16528f..c34ef4559b 100644
--- a/src/nm-logging.h
+++ b/src/nm-logging.h
@@ -163,7 +163,6 @@ gboolean nm_logging_setup (const char *level,
const char *domains,
char **bad_domains,
GError **error);
-void nm_logging_syslog_openlog (gboolean debug);
-void nm_logging_syslog_closelog (void);
+void nm_logging_syslog_openlog (const char *logging_backend);
#endif /* __NETWORKMANAGER_LOGGING_H__ */