summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2020-07-23 17:57:44 +0100
committerPhilip Withnall <pwithnall@endlessos.org>2020-10-07 14:04:08 +0100
commitb17b537a7de15ec66a0dd2b1c708409f415426a2 (patch)
tree8d2b1b7f64c11ae0011c11a8a36fcd85a2538ff8
parent10b0ece9d8428bde0583d28ed42e227ed353271f (diff)
downloadglib-b17b537a7de15ec66a0dd2b1c708409f415426a2.tar.gz
gmessages: Expose our default filtering as API
This allows programs that want to change how log messages are printed, such as gnome-terminal (gnome-terminal#42) and Flatpak, to override the log-writer or the legacy log-handler without having to reimplement the G_MESSAGES_DEBUG filtering logic. Signed-off-by: Simon McVittie <smcv@collabora.com>
-rw-r--r--docs/reference/glib/glib-sections.txt1
-rw-r--r--glib/gmessages.c119
-rw-r--r--glib/gmessages.h3
-rw-r--r--glib/tests/logging.c51
4 files changed, 148 insertions, 26 deletions
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 30e58de0c..6c1c86198 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -1485,6 +1485,7 @@ g_log_writer_journald
g_log_writer_standard_streams
g_log_writer_default
g_log_writer_default_set_use_stderr
+g_log_writer_default_would_drop
<SUBSECTION Private>
g_log_structured_standard
diff --git a/glib/gmessages.c b/glib/gmessages.c
index 440abd507..ec21d5d1d 100644
--- a/glib/gmessages.c
+++ b/glib/gmessages.c
@@ -127,7 +127,8 @@
* It is recommended that custom log writer functions re-use the
* `G_MESSAGES_DEBUG` environment variable, rather than inventing a custom one,
* so that developers can re-use the same debugging techniques and tools across
- * projects.
+ * projects. Since GLib 2.68, this can be implemented by dropping messages
+ * for which g_log_writer_default_would_drop() returns %TRUE.
*
* ## Testing for Messages ## {#testing-for-messages}
*
@@ -2617,6 +2618,95 @@ log_is_old_api (const GLogField *fields,
g_strcmp0 (fields[0].value, "1") == 0);
}
+/*
+ * Internal version of g_log_writer_default_would_drop(), which can
+ * read from either a log_domain or an array of fields. This avoids
+ * having to iterate through the fields if the @log_level is sufficient
+ * to make the decision.
+ */
+static gboolean
+should_drop_message (GLogLevelFlags log_level,
+ const char *log_domain,
+ const GLogField *fields,
+ gsize n_fields)
+{
+ /* Disable debug message output unless specified in G_MESSAGES_DEBUG. */
+ if (!(log_level & DEFAULT_LEVELS) && !(log_level >> G_LOG_LEVEL_USER_SHIFT))
+ {
+ const gchar *domains;
+ gsize i;
+
+ domains = g_getenv ("G_MESSAGES_DEBUG");
+
+ if ((log_level & INFO_LEVELS) == 0 ||
+ domains == NULL)
+ return TRUE;
+
+ if (log_domain == NULL)
+ {
+ for (i = 0; i < n_fields; i++)
+ {
+ if (g_strcmp0 (fields[i].key, "GLIB_DOMAIN") == 0)
+ {
+ log_domain = fields[i].value;
+ break;
+ }
+ }
+ }
+
+ if (strcmp (domains, "all") != 0 &&
+ (log_domain == NULL || !strstr (domains, log_domain)))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * g_log_writer_default_would_drop:
+ * @log_domain: (nullable): log domain
+ * @log_level: log level, either from #GLogLevelFlags, or a user-defined
+ * level
+ *
+ * Check whether g_log_writer_default() and g_log_default_handler() would
+ * ignore a message with the given domain and level.
+ *
+ * As with g_log_default_handler(), this function drops debug and informational
+ * messages unless their log domain (or `all`) is listed in the space-separated
+ * `G_MESSAGES_DEBUG` environment variable.
+ *
+ * This can be used when implementing log writers with the same filtering
+ * behaviour as the default, but a different destination or output format:
+ *
+ * |[<!-- language="C" -->
+ * if (g_log_writer_default_would_drop (log_level, log_domain))
+ * return G_LOG_WRITER_HANDLED;
+ * ]|
+ *
+ * or to skip an expensive computation if it is only needed for a debugging
+ * message, and `G_MESSAGES_DEBUG` is not set:
+ *
+ * |[<!-- language="C" -->
+ * if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
+ * {
+ * gchar *result = expensive_computation (my_object);
+ *
+ * g_debug ("my_object result: %s", result);
+ * g_free (result);
+ * }
+ * ]|
+ *
+ * Returns: %TRUE if the log message would be dropped by GLib's
+ * default log handlers
+ * Since: 2.68
+ */
+gboolean
+g_log_writer_default_would_drop (GLogLevelFlags log_level,
+ const char *log_domain)
+{
+ return should_drop_message (log_level, log_domain, NULL, 0);
+}
+
/**
* g_log_writer_default:
* @log_level: log level, either from #GLogLevelFlags, or a user-defined
@@ -2661,31 +2751,8 @@ g_log_writer_default (GLogLevelFlags log_level,
g_return_val_if_fail (fields != NULL, G_LOG_WRITER_UNHANDLED);
g_return_val_if_fail (n_fields > 0, G_LOG_WRITER_UNHANDLED);
- /* Disable debug message output unless specified in G_MESSAGES_DEBUG. */
- if (!(log_level & DEFAULT_LEVELS) && !(log_level >> G_LOG_LEVEL_USER_SHIFT))
- {
- const gchar *domains, *log_domain = NULL;
- gsize i;
-
- domains = g_getenv ("G_MESSAGES_DEBUG");
-
- if ((log_level & INFO_LEVELS) == 0 ||
- domains == NULL)
- return G_LOG_WRITER_HANDLED;
-
- for (i = 0; i < n_fields; i++)
- {
- if (g_strcmp0 (fields[i].key, "GLIB_DOMAIN") == 0)
- {
- log_domain = fields[i].value;
- break;
- }
- }
-
- if (strcmp (domains, "all") != 0 &&
- (log_domain == NULL || !strstr (domains, log_domain)))
- return G_LOG_WRITER_HANDLED;
- }
+ if (should_drop_message (log_level, NULL, fields, n_fields))
+ return G_LOG_WRITER_HANDLED;
/* Mark messages as fatal if they have a level set in
* g_log_set_always_fatal().
diff --git a/glib/gmessages.h b/glib/gmessages.h
index 29bc1736e..6a28443b4 100644
--- a/glib/gmessages.h
+++ b/glib/gmessages.h
@@ -244,6 +244,9 @@ GLogWriterOutput g_log_writer_default (GLogLevelFlags log_level,
GLIB_AVAILABLE_IN_2_68
void g_log_writer_default_set_use_stderr (gboolean use_stderr);
+GLIB_AVAILABLE_IN_2_68
+gboolean g_log_writer_default_would_drop (GLogLevelFlags log_level,
+ const char *log_domain);
/**
* G_DEBUG_HERE:
diff --git a/glib/tests/logging.c b/glib/tests/logging.c
index 1e9192bef..f16503ad1 100644
--- a/glib/tests/logging.c
+++ b/glib/tests/logging.c
@@ -139,6 +139,53 @@ test_default_handler_debug_stderr (void)
g_log ("foo", G_LOG_LEVEL_DEBUG, "6");
g_log ("bar", G_LOG_LEVEL_DEBUG, "6");
g_log ("baz", G_LOG_LEVEL_DEBUG, "6");
+
+ exit (0);
+}
+
+static void
+test_default_handler_would_drop (void)
+{
+ g_unsetenv ("G_MESSAGES_DEBUG");
+
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_ERROR, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_CRITICAL, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_WARNING, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_MESSAGE, "foo"));
+ g_assert_true (g_log_writer_default_would_drop (G_LOG_LEVEL_INFO, "foo"));
+ g_assert_true (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (1<<G_LOG_LEVEL_USER_SHIFT, "foo"));
+
+ g_setenv ("G_MESSAGES_DEBUG", "bar baz", TRUE);
+
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_ERROR, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_CRITICAL, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_WARNING, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_MESSAGE, "foo"));
+ g_assert_true (g_log_writer_default_would_drop (G_LOG_LEVEL_INFO, "foo"));
+ g_assert_true (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (1<<G_LOG_LEVEL_USER_SHIFT, "foo"));
+
+ g_setenv ("G_MESSAGES_DEBUG", "foo bar", TRUE);
+
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_ERROR, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_CRITICAL, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_WARNING, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_MESSAGE, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_INFO, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (1<<G_LOG_LEVEL_USER_SHIFT, "foo"));
+
+ g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_ERROR, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_CRITICAL, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_WARNING, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_MESSAGE, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_INFO, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "foo"));
+ g_assert_false (g_log_writer_default_would_drop (1<<G_LOG_LEVEL_USER_SHIFT, "foo"));
+
exit (0);
}
@@ -193,6 +240,9 @@ test_default_handler (void)
g_test_trap_subprocess ("/logging/default-handler/subprocess/0x400", 0, 0);
g_test_trap_assert_passed ();
g_test_trap_assert_stdout ("*LOG-0x400*message7*");
+
+ g_test_trap_subprocess ("/logging/default-handler/subprocess/would-drop", 0, 0);
+ g_test_trap_assert_passed ();
}
static void
@@ -600,6 +650,7 @@ main (int argc, char *argv[])
g_test_add_func ("/logging/default-handler/subprocess/debug", test_default_handler_debug);
g_test_add_func ("/logging/default-handler/subprocess/debug-stderr", test_default_handler_debug_stderr);
g_test_add_func ("/logging/default-handler/subprocess/0x400", test_default_handler_0x400);
+ g_test_add_func ("/logging/default-handler/subprocess/would-drop", test_default_handler_would_drop);
g_test_add_func ("/logging/warnings", test_warnings);
g_test_add_func ("/logging/fatal-log-mask", test_fatal_log_mask);
g_test_add_func ("/logging/set-handler", test_set_handler);