about summary refs log tree commit diff
path: root/src/logging/nm-logging.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
committerMichael Biebl <biebl@debian.org>2014-07-06 02:16:10 +0200
commit33491bc4279481db8ae47213e34a6d695a0e8830 (patch)
tree097d2b0fdff3fae6885381ae5e57a182cd8cbbba /src/logging/nm-logging.c
parent59c3714a494c3b3765657c0551ad82842d98a7d2 (diff)
Imported Upstream version 0.9.10.0 upstream/0.9.10.0
Diffstat (limited to 'src/logging/nm-logging.c')
-rw-r--r--src/logging/nm-logging.c358
1 files changed, 256 insertions, 102 deletions
diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c
index 79d47f13..1577f6ec 100644
--- a/src/logging/nm-logging.c
+++ b/src/logging/nm-logging.c
@@ -36,31 +36,40 @@
 
 #include "nm-logging.h"
 
+static void
+nm_log_handler (const gchar *log_domain,
+                GLogLevelFlags level,
+                const gchar *message,
+                gpointer ignored);
+
 #define LOGD_ALL \
 	(LOGD_PLATFORM | LOGD_RFKILL | LOGD_ETHER | LOGD_WIFI | LOGD_BT | LOGD_MB | \
 	 LOGD_DHCP4 | LOGD_DHCP6 | LOGD_PPP | LOGD_WIFI_SCAN | LOGD_IP4 | \
 	 LOGD_IP6 | LOGD_AUTOIP4 | LOGD_DNS | LOGD_VPN | LOGD_SHARING | \
 	 LOGD_SUPPLICANT | LOGD_AGENTS | LOGD_SETTINGS | LOGD_SUSPEND | \
-	 LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | LOGD_WIMAX | \
+	 LOGD_CORE | LOGD_DEVICE | LOGD_OLPC | LOGD_WIMAX | \
 	 LOGD_INFINIBAND | LOGD_FIREWALL | LOGD_ADSL | LOGD_BOND | \
-	 LOGD_VLAN | LOGD_BRIDGE | LOGD_CONCHECK)
+	 LOGD_VLAN | LOGD_BRIDGE | LOGD_DBUS_PROPS | LOGD_TEAM | LOGD_CONCHECK | \
+	 LOGD_DCB | LOGD_DISPATCH)
 
-#define LOGD_DEFAULT (LOGD_ALL & ~LOGD_WIFI_SCAN)
+#define LOGD_DEFAULT (LOGD_ALL & ~(LOGD_WIFI_SCAN | LOGD_DBUS_PROPS))
 
-static guint32 log_level = LOGL_INFO | LOGL_WARN | LOGL_ERR;
-static guint32 log_domains = LOGD_DEFAULT;
+static guint32 log_level = LOGL_INFO;
+static char *log_domains;
+static guint64 logging[LOGL_MAX];
+static gboolean logging_set_up;
+static gboolean syslog_opened;
 
 typedef struct {
-	guint32 num;
+	guint64 num;
 	const char *name;
 } LogDesc;
 
-static const LogDesc level_descs[] = {
-	{ LOGL_ERR, "ERR" },
-	{ LOGL_WARN | LOGL_ERR, "WARN" },
-	{ LOGL_INFO | LOGL_WARN | LOGL_ERR, "INFO" },
-	{ LOGL_DEBUG | LOGL_INFO | LOGL_WARN | LOGL_ERR, "DEBUG" },
-	{ 0, NULL }
+static const char *level_names[LOGL_MAX] = {
+	[LOGL_DEBUG] = "DEBUG",
+	[LOGL_INFO] = "INFO",
+	[LOGL_WARN] = "WARN",
+	[LOGL_ERR] = "ERR",
 };
 
 static const LogDesc domain_descs[] = {
@@ -87,7 +96,7 @@ static const LogDesc domain_descs[] = {
 	{ LOGD_SUSPEND,   "SUSPEND" },
 	{ LOGD_CORE,      "CORE" },
 	{ LOGD_DEVICE,    "DEVICE" },
-	{ LOGD_OLPC_MESH, "OLPC" },
+	{ LOGD_OLPC,      "OLPC" },
 	{ LOGD_WIMAX,     "WIMAX" },
 	{ LOGD_INFINIBAND,"INFINIBAND" },
 	{ LOGD_FIREWALL,  "FIREWALL" },
@@ -95,7 +104,11 @@ static const LogDesc domain_descs[] = {
 	{ LOGD_BOND,      "BOND" },
 	{ LOGD_VLAN,      "VLAN" },
 	{ LOGD_BRIDGE,    "BRIDGE" },
+	{ LOGD_DBUS_PROPS,"DBUS_PROPS" },
+	{ LOGD_TEAM,      "TEAM" },
 	{ LOGD_CONCHECK,  "CONCHECK" },
+	{ LOGD_DCB,       "DCB" },
+	{ LOGD_DISPATCH,  "DISPATCH" },
 	{ 0, NULL }
 };
 
@@ -119,95 +132,157 @@ nm_logging_error_quark (void)
 
 /************************************************************************/
 
+static gboolean
+match_log_level (const char  *level,
+                 guint32     *out_level,
+                 GError     **error)
+{
+	int i;
+
+	for (i = 0; i < LOGL_MAX; i++) {
+		if (!g_ascii_strcasecmp (level_names[i], level)) {
+			*out_level = i;
+			return TRUE;
+		}
+	}
+
+	g_set_error (error, NM_LOGGING_ERROR, NM_LOGGING_ERROR_UNKNOWN_LEVEL,
+	             _("Unknown log level '%s'"), level);
+	return FALSE;
+}
+
 gboolean
-nm_logging_setup (const char *level, const char *domains, GError **error)
+nm_logging_setup (const char  *level,
+                  const char  *domains,
+                  char       **bad_domains,
+                  GError     **error)
 {
+	GString *unrecognized = NULL;
+	guint64 new_logging[LOGL_MAX];
+	guint32 new_log_level = log_level;
 	char **tmp, **iter;
-	guint32 new_domains = 0;
+	int i;
 
-	/* levels */
-	if (level && strlen (level)) {
-		gboolean found = FALSE;
-		const LogDesc *diter;
+	logging_set_up = TRUE;
 
-		for (diter = &level_descs[0]; diter->name; diter++) {
-			if (!strcasecmp (diter->name, level)) {
-				log_level = diter->num;
-				found = TRUE;
-				break;
-			}
-		}
+	for (i = 0; i < LOGL_MAX; i++)
+		new_logging[i] = 0;
 
-		if (!found) {
-			g_set_error (error, NM_LOGGING_ERROR, NM_LOGGING_ERROR_UNKNOWN_LEVEL,
-			             _("Unknown log level '%s'"), level);
+	/* levels */
+	if (level && *level) {
+		if (!match_log_level (level, &new_log_level, error))
 			return FALSE;
-		}
 	}
 
 	/* domains */
-	if (domains && strlen (domains)) {
-		tmp = g_strsplit_set (domains, ", ", 0);
-		for (iter = tmp; iter && *iter; iter++) {
-			const LogDesc *diter;
-			gboolean found = FALSE;
-
-			if (!strlen (*iter))
-				continue;
+	if (!domains || !*domains)
+		domains = log_domains ? log_domains : "DEFAULT";
 
+	tmp = g_strsplit_set (domains, ", ", 0);
+	for (iter = tmp; iter && *iter; iter++) {
+		const LogDesc *diter;
+		guint32 domain_log_level;
+		guint64 bits;
+		char *p;
+
+		if (!strlen (*iter))
+			continue;
+
+		p = strchr (*iter, ':');
+		if (p) {
+			*p = '\0';
+			if (!match_log_level (p + 1, &domain_log_level, error)) {
+				g_strfreev (tmp);
+				return FALSE;
+			}
+		} else
+			domain_log_level = new_log_level;
+
+		bits = 0;
+
+		/* Check for combined domains */
+		if (!g_ascii_strcasecmp (*iter, LOGD_ALL_STRING))
+			bits = LOGD_ALL;
+		else if (!g_ascii_strcasecmp (*iter, LOGD_DEFAULT_STRING))
+			bits = LOGD_DEFAULT;
+		else if (!g_ascii_strcasecmp (*iter, LOGD_DHCP_STRING))
+			bits = LOGD_DHCP;
+		else if (!g_ascii_strcasecmp (*iter, LOGD_IP_STRING))
+			bits = LOGD_IP;
+
+		/* Check for compatibility domains */
+		else if (!g_ascii_strcasecmp (*iter, "HW"))
+			bits = LOGD_PLATFORM;
+
+		else {
 			for (diter = &domain_descs[0]; diter->name; diter++) {
-				if (!strcasecmp (diter->name, *iter)) {
-					new_domains |= diter->num;
-					found = TRUE;
+				if (!g_ascii_strcasecmp (diter->name, *iter)) {
+					bits = diter->num;
 					break;
 				}
 			}
+		}
 
-			/* Check for combined domains */
-			if (!strcasecmp (*iter, LOGD_ALL_STRING)) {
-				new_domains = LOGD_ALL;
-				found = TRUE;
-			} else if (!strcasecmp (*iter, LOGD_DEFAULT_STRING)) {
-				new_domains = LOGD_DEFAULT;
-				found = TRUE;
-			} else if (!strcasecmp (*iter, LOGD_DHCP_STRING)) {
-				new_domains |= LOGD_DHCP;
-				found = TRUE;
-			} else if (!strcasecmp (*iter, LOGD_IP_STRING)) {
-				new_domains |= LOGD_IP;
-				found = TRUE;
-			}
-
-			/* Check for compatibility domains */
-			if (!strcasecmp (*iter, "HW")) {
-				new_domains |= LOGD_PLATFORM;
-				found = TRUE;
-			}
-
-			if (!found) {
+		if (!bits) {
+			if (!bad_domains) {
 				g_set_error (error, NM_LOGGING_ERROR, NM_LOGGING_ERROR_UNKNOWN_DOMAIN,
 				             _("Unknown log domain '%s'"), *iter);
 				return FALSE;
 			}
+
+			if (unrecognized)
+				g_string_append (unrecognized, ", ");
+			else
+				unrecognized = g_string_new (NULL);
+			g_string_append (unrecognized, *iter);
+			continue;
 		}
-		g_strfreev (tmp);
-		log_domains = new_domains;
+
+		for (i = 0; i < domain_log_level; i++)
+			new_logging[i] &= ~bits;
+		for (i = domain_log_level; i < LOGL_MAX; i++)
+			new_logging[i] |= bits;
+	}
+	g_strfreev (tmp);
+
+	if (log_domains != (char *)domains) {
+		g_free (log_domains);
+		log_domains = g_strdup (domains);
 	}
 
+	log_level = new_log_level;
+	for (i = 0; i < LOGL_MAX; i++)
+		logging[i] = new_logging[i];
+
+	if (unrecognized)
+		*bad_domains = g_string_free (unrecognized, FALSE);
+
 	return TRUE;
 }
 
-const char *
+char *
 nm_logging_level_to_string (void)
 {
-	const LogDesc *diter;
+	return g_strdup (level_names[log_level]);
+}
+
+const char *
+nm_logging_all_levels_to_string (void)
+{
+	static GString *str;
+
+	if (G_UNLIKELY (!str)) {
+		int i;
 
-	for (diter = &level_descs[0]; diter->name; diter++) {
-		if (diter->num == log_level)
-			return diter->name;
+		str = g_string_new (NULL);
+		for (i = 0; i < LOGL_MAX; i++) {
+			if (str->len)
+				g_string_append_c (str, ',');
+			g_string_append (str, level_names[i]);
+		}
 	}
-	g_warn_if_reached ();
-	return "";
+
+	return str->str;
 }
 
 char *
@@ -215,61 +290,135 @@ nm_logging_domains_to_string (void)
 {
 	const LogDesc *diter;
 	GString *str;
+	int i;
+
+	/* We don't just return g_strdup (log_domains) because we want to expand
+	 * "DEFAULT" and "ALL".
+	 */
 
 	str = g_string_sized_new (75);
 	for (diter = &domain_descs[0]; diter->name; diter++) {
-		if (diter->num & log_domains) {
-			if (str->len)
-				g_string_append_c (str, ',');
-			g_string_append (str, diter->name);
+		/* If it's set for any lower level, it will also be set for LOGL_ERR */
+		if (!(diter->num & logging[LOGL_ERR]))
+			continue;
+
+		if (str->len)
+			g_string_append_c (str, ',');
+		g_string_append (str, diter->name);
+
+		/* 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]);
+				break;
+			}
+		}
+		/* Check if it's logging at a higher level than the default. */
+		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]);
+					break;
+				}
+			}
 		}
 	}
 	return g_string_free (str, FALSE);
 }
 
-gboolean
-nm_logging_level_enabled (guint32 level)
+const char *
+nm_logging_all_domains_to_string (void)
 {
-	return !!(log_level & level);
+	static GString *str;
+
+	if (G_UNLIKELY (!str)) {
+		const LogDesc *diter;
+
+		str = g_string_new (LOGD_DEFAULT_STRING);
+		for (diter = &domain_descs[0]; diter->name; diter++) {
+			g_string_append_c (str, ',');
+			g_string_append (str, diter->name);
+			if (diter->num == LOGD_DHCP6)
+				g_string_append (str, "," LOGD_DHCP_STRING);
+			else if (diter->num == LOGD_IP6)
+				g_string_append (str, "," LOGD_IP_STRING);
+		}
+		g_string_append (str, "," LOGD_ALL_STRING);
+	}
+
+	return str->str;
 }
 
 gboolean
-nm_logging_domain_enabled (guint32 domain)
+nm_logging_enabled (guint32 level, guint64 domain)
 {
-	return !!(log_domains & domain);
+	g_return_val_if_fail (level < LOGL_MAX, FALSE);
+
+	return !!(logging[level] & domain);
 }
 
 void
 _nm_log (const char *loc,
          const char *func,
-         guint32 domain,
+         guint64 domain,
          guint32 level,
          const char *fmt,
          ...)
 {
 	va_list args;
 	char *msg;
+	char *fullmsg = NULL;
 	GTimeVal tv;
+	int syslog_level = LOG_INFO;
+	int g_log_level = G_LOG_LEVEL_INFO;
 
-	if (!(log_level & level) || !(log_domains & domain))
+	g_return_if_fail (level < LOGL_MAX);
+
+	if (G_UNLIKELY (!logging_set_up))
+		nm_logging_setup ("INFO", "DEFAULT", NULL, NULL);
+
+	if (!(logging[level] & domain))
 		return;
 
 	va_start (args, fmt);
 	msg = g_strdup_vprintf (fmt, args);
 	va_end (args);
 
-	if ((log_level & LOGL_DEBUG) && (level == LOGL_DEBUG)) {
+	switch (level) {
+	case LOGL_DEBUG:
 		g_get_current_time (&tv);
-		syslog (LOG_INFO, "<debug> [%ld.%ld] [%s] %s(): %s", tv.tv_sec, tv.tv_usec, loc, func, msg);
-	} else if ((log_level & LOGL_INFO) && (level == LOGL_INFO))
-		syslog (LOG_INFO, "<info> %s", msg);
-	else if ((log_level & LOGL_WARN) && (level == LOGL_WARN))
-		syslog (LOG_WARNING, "<warn> %s", msg);
-	else if ((log_level & LOGL_ERR) && (level == LOGL_ERR)) {
+		syslog_level = LOG_INFO;
+		g_log_level = G_LOG_LEVEL_DEBUG;
+		fullmsg = g_strdup_printf ("<debug> [%ld.%06ld] [%s] %s(): %s", tv.tv_sec, tv.tv_usec, loc, 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);
-		syslog (LOG_ERR, "<error> [%ld.%ld] [%s] %s(): %s", tv.tv_sec, tv.tv_usec, loc, func, msg);
+		fullmsg = g_strdup_printf ("<error> [%ld.%06ld] [%s] %s(): %s", tv.tv_sec, tv.tv_usec, loc, func, msg);
+		break;
+	default:
+		g_assert_not_reached ();
 	}
+
+	if (syslog_opened)
+		syslog (syslog_level, "%s", fullmsg);
+	else
+		g_log (G_LOG_DOMAIN, g_log_level, "%s", fullmsg);
+
 	g_free (msg);
+	g_free (fullmsg);
 }
 
 /************************************************************************/
@@ -282,7 +431,7 @@ nm_log_handler (const gchar *log_domain,
 {
 	int syslog_priority;	
 
-	switch (level) {
+	switch (level & G_LOG_LEVEL_MASK) {
 	case G_LOG_LEVEL_ERROR:
 		syslog_priority = LOG_CRIT;
 		break;
@@ -308,21 +457,26 @@ nm_log_handler (const gchar *log_domain,
 }
 
 void
-nm_logging_start (gboolean become_daemon)
+nm_logging_syslog_openlog (gboolean debug)
 {
-	if (become_daemon)
-		openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON);
-	else
+	if (debug)
 		openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
+	else
+		openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON);
 
-	g_log_set_handler (G_LOG_DOMAIN, 
-	                   G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
-	                   nm_log_handler,
-	                   NULL);
+	if (!syslog_opened) {
+		syslog_opened = TRUE;
+
+		g_log_set_handler (G_LOG_DOMAIN,
+		                   G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
+		                   nm_log_handler,
+		                   NULL);
+	}
 }
 
 void
-nm_logging_shutdown (void)
+nm_logging_syslog_closelog (void)
 {
-	closelog ();
+	if (syslog_opened)
+		closelog ();
 }