diff options
author | Thomas Haller <thaller@redhat.com> | 2015-07-14 15:59:13 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-07-14 15:59:13 +0200 |
commit | 59ca132b3aafd7cabcdfe045ac966279c96a92b2 (patch) | |
tree | 91ef2a673c02c5832a47d077fe18f2a4d7dc35b6 | |
parent | 5cc2eabe5d24c8d9fe30aa675d48c7fa121d7c93 (diff) | |
parent | 81f3c36f231c34132a542aaf37c0ffd7ee30baaf (diff) | |
download | NetworkManager-59ca132b3aafd7cabcdfe045ac966279c96a92b2.tar.gz |
logging: merge branch 'th/logging-sd-journal-bgo752136'
https://bugzilla.gnome.org/show_bug.cgi?id=752136
-rw-r--r-- | configure.ac | 45 | ||||
-rw-r--r-- | man/NetworkManager.conf.xml.in | 14 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/devices/nm-device.c | 12 | ||||
-rw-r--r-- | src/main.c | 13 | ||||
-rw-r--r-- | src/nm-config-data.c | 21 | ||||
-rw-r--r-- | src/nm-config-data.h | 1 | ||||
-rw-r--r-- | src/nm-config.c | 10 | ||||
-rw-r--r-- | src/nm-config.h | 2 | ||||
-rw-r--r-- | src/nm-iface-helper.c | 8 | ||||
-rw-r--r-- | src/nm-logging.c | 282 | ||||
-rw-r--r-- | src/nm-logging.h | 3 |
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__ */ |