Add Geary.Loggable interface for objects that can log and be logged

For now, just implement using existing non-structured logging calls.
This commit is contained in:
Michael Gratton 2018-12-29 12:12:32 +11:00 committed by Michael James Gratton
parent 6e137eb649
commit f7c833242a
4 changed files with 125 additions and 7 deletions

View file

@ -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

View file

@ -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);
}
}

View file

@ -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',

View file

@ -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);
}
}