[gnome-devel-docs] programming-guidelines: Add a page on log output



commit 100e4c37125e49d036450123e624c3a35be6f91c
Author: Philip Withnall <philip withnall collabora co uk>
Date:   Mon Feb 9 16:47:01 2015 +0000

    programming-guidelines: Add a page on log output
    
    https://bugzilla.gnome.org/show_bug.cgi?id=376123

 programming-guidelines/C/logging.page |  219 +++++++++++++++++++++++++++++++++
 programming-guidelines/Makefile.am    |    1 +
 2 files changed, 220 insertions(+), 0 deletions(-)
---
diff --git a/programming-guidelines/C/logging.page b/programming-guidelines/C/logging.page
new file mode 100644
index 0000000..b0354f1
--- /dev/null
+++ b/programming-guidelines/C/logging.page
@@ -0,0 +1,219 @@
+<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#coding-style"/>
+
+    <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="coding-conventions#gerror-usage"><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>
diff --git a/programming-guidelines/Makefile.am b/programming-guidelines/Makefile.am
index 910aec9..44428b8 100644
--- a/programming-guidelines/Makefile.am
+++ b/programming-guidelines/Makefile.am
@@ -14,6 +14,7 @@ HELP_FILES = \
        documentation.page \
        file-system.page \
        index.page \
+       logging.page \
        memory-management.page \
        namespacing.page \
        parallel-installability.page \


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]