diff options
author | Simon McVittie <smcv@collabora.com> | 2020-07-23 17:57:44 +0100 |
---|---|---|
committer | Philip Withnall <pwithnall@endlessos.org> | 2020-10-07 14:04:08 +0100 |
commit | b17b537a7de15ec66a0dd2b1c708409f415426a2 (patch) | |
tree | 8d2b1b7f64c11ae0011c11a8a36fcd85a2538ff8 | |
parent | 10b0ece9d8428bde0583d28ed42e227ed353271f (diff) | |
download | glib-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.txt | 1 | ||||
-rw-r--r-- | glib/gmessages.c | 119 | ||||
-rw-r--r-- | glib/gmessages.h | 3 | ||||
-rw-r--r-- | glib/tests/logging.c | 51 |
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); |