<page xmlns="http://projectmallard.org/1.0/"
      xmlns:its="http://www.w3.org/2005/11/its"
      xmlns:xi="http://www.w3.org/2003/XInclude"
      type="topic"
      id="logging">

  <info>
    <link type="guide" xref="index#specific-how-tos"/>

    <credit type="author copyright">
      <name>Philip Withnall</name>
      <email its:translate="no">philip.withnall@collabora.co.uk</email>
      <years>2015</years>
    </credit>

    <include href="cc-by-sa-3-0.xml" xmlns="http://www.w3.org/2001/XInclude"/>

    <desc>
      Logging debug and information output from libraries and programs
    </desc>
  </info>

  <title>Logging</title>

  <synopsis>
    <title>Summary</title>

    <p>
      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.
    </p>

    <list>
      <item><p>
        Use the GLib logging framework instead of logging directly to stderr and
        stdout. (<link xref="#glib-logging-framework"/>)
      </p></item>
      <item><p>
        If systemd can be a dependency of the project, consider logging directly
        to the journal. (<link xref="#journald-integration"/>)
      </p></item>
      <item><p>
        Do not implement log rotation and deletion; leave that to system
        services. (<link xref="#log-rotation"/>)
      </p></item>
    </list>
  </synopsis>

  <section id="glib-logging-framework">
    <title>GLib Logging Framework</title>

    <p>
      GLib provides
      <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html">a
      logging framework</link> based around the
      <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log"><code>g_log()</code></link>
      function, with convenience wrappers
      <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-debug"><code>g_debug()</code></link>,
      <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-message"><code>g_message()</code></link>,
      <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-warning"><code>g_warning()</code></link>
      and
      <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-error"><code>g_error()</code></link>.
      The GLib logging framework has a few useful features:
    </p>
    <list>
      <item><p>
        Programmatic redirection of log messages using
        <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log-set-handler"><code>g_log_set_handler()</code></link>.
      </p></item>
      <item><p>
        Multiple logging domains, which can be processed separately.
      </p></item>
      <item><p>
        Multiple log levels, which can be processed separately. For example,
        this allows debug messages to be turned on and off at runtime.
      </p></item>
      <item><p>
        Support for automatically aborting a program on ‘fatal’ messages.
      </p></item>
    </list>

    <p>
      These should be used in preference to functions like
      <code>printf()</code>,
      <link href="https://developer.gnome.org/glib/stable/glib-Warnings-and-Assertions.html#g-print"><code>g_print()</code></link>
      and
      <link href="https://developer.gnome.org/glib/stable/glib-Warnings-and-Assertions.html#g-printerr"><code>g_printerr()</code></link>,
      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.
    </p>

    <p>
      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.
    </p>

    <p>
      To use the GLib logging framework, define
      <link href="https://developer.gnome.org/glib/stable/glib-Message-Logging.html#G-LOG-DOMAIN:CAPS"><code>G_LOG_DOMAIN</code></link>
      for the project so it’s unique from all other projects. Call
      <code>g_debug("Message")</code> to log a debug message.
    </p>

    <p>
      If the default GLib log handlers are not sufficient, for example if log
      messages need to be in a custom format or
      <link xref="#journald-integration">journald integration</link> is needed,
      set up a log handler with the following code:
    </p>
    <code mime="text/x-csrc">
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 &amp;&amp; (log_level &amp; G_LOG_LEVEL_DEBUG))
    {
      return;
    }

  log_level_str = log_level_to_string (log_level &amp; G_LOG_LEVEL_MASK);

  /* Use g_printerr() for warnings and g_print() otherwise. */
  if (flags &lt;= 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);</code>

    <section id="exceptions">
      <title>Exceptions</title>

      <list>
        <item><p>
          Do not use <code>g_message()</code> in normal code to print output.
          Printing output should be done at the top level of an application,
          using <code>g_print()</code>, and should be quite rare; i.e. only done
          in command line applications.
        </p></item>
        <item><p>
          Do not use  <code>g_warning()</code> in library code. Use
          <link xref="gerror"><code>GError</code>s</link> instead.
        </p></item>
        <item><p>
          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.
        </p></item>
      </list>
    </section>
  </section>

  <section id="journald-integration">
    <title>journald Integration</title>

    <p>
      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 <code>systemd-journal</code> as a
      dependency to a project, the project’s log handling function could be
      extended to use
      <link href="http://0pointer.de/public/systemd-man/sd_journal_send.html"><code>sd_journal_print()</code>
      and <code>sd_journal_send()</code></link> instead of
      <code>g_print()</code> and <code>g_printerr()</code>.
    </p>

    <p>
      For more information, see this
      <link href="http://0pointer.de/blog/projects/journal-submit.html">article
      on logging to the journal</link>.
    </p>
  </section>

  <section id="log-rotation">
    <title>Log Rotation</title>

    <p>
      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 <cmd>logrotate</cmd> or <cmd>systemd-journald</cmd>.
    </p>
  </section>
</page>
