[geary/wip/structured-logging: 1/7] Add Geary.Loggable interface for objects that can log and be logged



commit f7c833242af5bf319caaef6644bf7e453a5b0654
Author: Michael Gratton <mike vee net>
Date:   Sat Dec 29 12:12:32 2018 +1100

    Add Geary.Loggable interface for objects that can log and be logged
    
    For now, just implement using existing non-structured logging calls.

 po/POTFILES.in                     |   1 +
 src/engine/api/geary-logging.vala  |  24 ++++++---
 src/engine/meson.build             |   1 +
 src/engine/util/util-loggable.vala | 106 +++++++++++++++++++++++++++++++++++++
 4 files changed, 125 insertions(+), 7 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index cc42fb14..b73f99bf 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -389,6 +389,7 @@ src/engine/util/util-imap-utf7.vala
 src/engine/util/util-inet.vala
 src/engine/util/util-iterable.vala
 src/engine/util/util-js.vala
+src/engine/util/util-loggable.vala
 src/engine/util/util-numeric.vala
 src/engine/util/util-object.vala
 src/engine/util/util-reference-semantics.vala
diff --git a/src/engine/api/geary-logging.vala b/src/engine/api/geary-logging.vala
index 652b7005..406485ca 100644
--- a/src/engine/api/geary-logging.vala
+++ b/src/engine/api/geary-logging.vala
@@ -14,11 +14,12 @@
 namespace Geary.Logging {
 
 
+/** The logging domain for the engine. */
+public const string DOMAIN = "Geary";
+
 /** Specifies the default number of log records retained. */
 public const uint DEFAULT_MAX_LOG_BUFFER_LENGTH = 4096;
 
-private const string DOMAIN = "Geary";
-
 /**
  * Denotes a type of log message.
  *
@@ -172,31 +173,40 @@ public inline bool are_all_flags_set(Flag flags) {
 [PrintfFormat]
 public inline void error(Flag flags, string fmt, ...) {
     if (logging_flags.is_any_set(flags))
-        logv(DOMAIN, LogLevelFlags.LEVEL_ERROR, fmt, va_list());
+        GLib.logv(DOMAIN, LogLevelFlags.LEVEL_ERROR, fmt, va_list());
 }
 
 [PrintfFormat]
 public inline void critical(Flag flags, string fmt, ...) {
     if (logging_flags.is_any_set(flags))
-        logv(DOMAIN, LogLevelFlags.LEVEL_CRITICAL, fmt, va_list());
+        GLib.logv(DOMAIN, LogLevelFlags.LEVEL_CRITICAL, fmt, va_list());
 }
 
 [PrintfFormat]
 public inline void warning(Flag flags, string fmt, ...) {
     if (logging_flags.is_any_set(flags))
-        logv(DOMAIN, LogLevelFlags.LEVEL_WARNING, fmt, va_list());
+        GLib.logv(DOMAIN, LogLevelFlags.LEVEL_WARNING, fmt, va_list());
 }
 
 [PrintfFormat]
 public inline void message(Flag flags, string fmt, ...) {
     if (logging_flags.is_any_set(flags))
-        logv(DOMAIN, LogLevelFlags.LEVEL_MESSAGE, fmt, va_list());
+        GLib.logv(DOMAIN, LogLevelFlags.LEVEL_MESSAGE, fmt, va_list());
 }
 
 [PrintfFormat]
 public inline void debug(Flag flags, string fmt, ...) {
     if (logging_flags.is_any_set(flags)) {
-        logv(DOMAIN, LogLevelFlags.LEVEL_DEBUG, fmt, va_list());
+        GLib.logv(DOMAIN, LogLevelFlags.LEVEL_DEBUG, fmt, va_list());
+    }
+}
+
+public inline void logv(Flag flags,
+                        GLib.LogLevelFlags level,
+                        string fmt,
+                        va_list args) {
+    if (logging_flags.is_any_set(flags)) {
+        GLib.logv(DOMAIN, level, fmt, args);
     }
 }
 
diff --git a/src/engine/meson.build b/src/engine/meson.build
index d413e509..71815983 100644
--- a/src/engine/meson.build
+++ b/src/engine/meson.build
@@ -307,6 +307,7 @@ geary_engine_vala_sources = files(
   'util/util-inet.vala',
   'util/util-iterable.vala',
   'util/util-js.vala',
+  'util/util-loggable.vala',
   'util/util-numeric.vala',
   'util/util-object.vala',
   'util/util-reference-semantics.vala',
diff --git a/src/engine/util/util-loggable.vala b/src/engine/util/util-loggable.vala
new file mode 100644
index 00000000..d220d397
--- /dev/null
+++ b/src/engine/util/util-loggable.vala
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2018 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+/**
+ * Mixin interface for objects that support structured logging.
+ *
+ * Loggable objects provide both a standard means to obtain a string
+ * representation of the object for display to humans, and keep a weak
+ * reference to some parent loggable, enabling this context to be
+ * automatically added to logging calls. For example, if a Foo object
+ * is the loggable parent of a Bar object, log calls made by Bar will
+ * automatically be decorated with Foo.
+ */
+public interface Geary.Loggable : GLib.Object {
+
+
+    /**
+     * Default flags to use for this loggable when logging messages.
+     */
+    public abstract Logging.Flag loggable_flags { get; protected set; }
+
+    /**
+     * The parent of this loggable.
+     *
+     * If not null, the parent and its ancestors recursively will be
+     * added to to log message context.
+     */
+    public abstract Loggable? loggable_parent { get; }
+
+    /**
+     * Returns a string representation of the service, for debugging.
+     */
+    public abstract string to_string();
+
+
+    /**
+     * Logs a debug-level log message with this object as context.
+     */
+    [PrintfFormat]
+    public inline void debug(string fmt, ...) {
+        log_structured(
+            this.loggable_flags, LogLevelFlags.LEVEL_DEBUG, fmt, va_list()
+        );
+    }
+
+    /**
+     * Logs a message-level log message with this object as context.
+     */
+    [PrintfFormat]
+    public inline void message(string fmt, ...) {
+        log_structured(
+            this.loggable_flags, LogLevelFlags.LEVEL_MESSAGE, fmt, va_list()
+        );
+    }
+
+    /**
+     * Logs a warning-level log message with this object as context.
+     */
+    [PrintfFormat]
+    public inline void warning(string fmt, ...) {
+        log_structured(
+            this.loggable_flags, LogLevelFlags.LEVEL_WARNING, fmt, va_list()
+        );
+    }
+
+    /**
+     * Logs a error-level log message with this object as context.
+     */
+    [PrintfFormat]
+    [NoReturn]
+    public inline void error(string fmt, ...) {
+        log_structured(
+            this.loggable_flags, LogLevelFlags.LEVEL_ERROR, fmt, va_list()
+        );
+    }
+
+    /**
+     * Logs a critical-level log message with this object as context.
+     */
+    [PrintfFormat]
+    public inline void critical(string fmt, ...) {
+        log_structured(
+            this.loggable_flags, LogLevelFlags.LEVEL_CRITICAL, fmt, va_list()
+        );
+    }
+
+    private inline void log_structured(Logging.Flag flags,
+                                       GLib.LogLevelFlags levels,
+                                       string fmt,
+                                       va_list args) {
+        GLib.StringBuilder message = new GLib.StringBuilder(fmt);
+        Loggable? decorator = this;
+        while (decorator != null) {
+            message.prepend_c(' ');
+            message.prepend(decorator.to_string());
+            decorator = decorator.loggable_parent;
+        }
+
+        Logging.logv(flags, levels, message.str, args);
+    }
+
+}


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