Philip Withnall
philip.withnall@collabora.co.uk 2015
Logga felsöknings- och informationsutdata från bibliotek och program
Anders Jonsson
anders.jonsson@norsjovallen.se 2018

# Loggning

#

        Sammanfattning

          Logging debug and informational output from libraries and programs is an
          open problem, and there are various methods for converting multiple
          streams of log output into the customary stdout and stderr streams. Below
          are some suggestions for how to implement logging. However, the most
          important thing is to ensure that logging is consistent, so that log data
          can be accessed and searched with a minimum of effort, since that’s what
          it’s used for. Using different logging mechanisms and formats in different
          projects is not the right approach.

          Använd GLibs ramverk för loggning istället för att logga direkt till stderr och stdout. ()

            If systemd can be a dependency of the project, consider logging directly
            to the journal. ()

          Implementera inte rotation och borttagning av loggar, lämna det till systemtjänster. ()

# GLib-ramverk för loggning

GLib provides a logging framework based around the `g_log()` function, with convenience wrappers `g_debug()`, `g_message()`, `g_warning()` and `g_error()`. The GLib logging framework has a few useful features:

Programmatic redirection of log messages using `g_log_set_handler()`.

Multiple logging domains, which can be processed separately.

Multiple log levels, which can be processed separately. For example, this allows debug messages to be turned on and off at runtime.

Support for automatically aborting a program on ‘fatal’ messages.

These should be used in preference to functions like `printf()`, `g_print()` and `g_printerr()`, due to their enhanced flexibility. The logging functions allow log processing to be done in code, rather than by external shell scripting, which simplifies everything.

A key reason to use the logging framework is that it is used in GLib and other related libraries already; by using it, all log messages are then going through the same system and can be processed similarly.

To use the GLib logging framework, define `G_LOG_DOMAIN` for the project so it’s unique from all other projects. Call `g_debug("Message")` to log a debug message.

If the default GLib log handlers are not sufficient, for example if log messages need to be in a custom format or journald integration is needed, set up a log handler with the following code:

static const gchar * log_level_to_string (GLogLevelFlags level) { switch (level) { case G_LOG_LEVEL_ERROR: return "ERROR"; case G_LOG_LEVEL_CRITICAL: return "CRITICAL"; case G_LOG_LEVEL_WARNING: return "WARNING"; case G_LOG_LEVEL_MESSAGE: return "MESSAGE"; case G_LOG_LEVEL_INFO: return "INFO"; case G_LOG_LEVEL_DEBUG: return "DEBUG"; default: return "UNKNOWN"; } }

static void log_handler_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { const gchar *log_level_str;

/* Ignore debug messages if disabled. */ if (!debug_enabled && (log_level & G_LOG_LEVEL_DEBUG)) { return; }

log_level_str = log_level_to_string (log_level & G_LOG_LEVEL_MASK);

/* Use g_printerr() for warnings and g_print() otherwise. */ if (flags <= G_LOG_LEVEL_WARNING) { g_printerr ("%s: %s: %s\n", log_domain, log_level_str, message); } else { g_print ("%s: %s: %s\n", log_domain, log_level_str, message); } }

g_log_set_handler ("log-domain", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, log_handler_cb, NULL);

## Undantag

Do not use `g_message()` in normal code to print output. Printing output should be done at the top level of an application, using `g_print()`, and should be quite rare; i.e. only done in command line applications.

Använd inte `g_warning()` i bibliotekskod. Använd `GError` istället.

Similarly, do not set up log handlers in library code. Log messages should propagate through library code and be handled in a log handler at the top level of an application.

# journald-integration

Compared to conventional syslog-style logs, journald supports storage of structured logging data, which can make post-hoc analysis of logs much easier. If it’s possible to add `systemd-journal` as a dependency to a project, the project’s log handling function could be extended to use `sd_journal_print()` and `sd_journal_send()` instead of `g_print()` and `g_printerr()`.

För mer information, se denna artikel om att logga till journalen.

# Rotation av loggar

Log file rotation is one feature which is out of scope of the GLib logging system. It should be handled by the normal system logging mechanisms, such as logrotate or systemd-journald.