gnucash/libgnucash/engine/qoflog.h

313 lines
10 KiB
C

/* qof-log.h
* Author: Rob Clark <rclark@cs.hmc.edu>
* Copyright (C) 1998-2003 Linas Vepstas <linas@linas.org>
* Copyright 2005 Neil Williams <linux@codehelp.co.uk>
* Copyright 2007 Joshua Sled <jsled@asynchronous.org>
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
/**
* @addtogroup Logging
* @{
* @ingroup QOF
* @brief Logging and tracing facility.
* @sa "Logging overhaul" announcement <https://lists.gnucash.org/pipermail/gnucash-devel/2007-February/019836.html>
*
* qof_log_init(void) installs a handler that interprets the "log_domain"
* as a "."-separated path. Log level thresholds can be set for each level
* in the tree. When a message is logged, the longest level match is
* found, and used as the threshold.
*
* For instance, we can set the levels as such:
* @verbatim
"qof" = WARN
"gnc" = WARN
"gnc.ui" = INFO
"gnc.ui.plugin-page.sx-list" = DEBUG
@endverbatim
*
* When code in the log_module of "gnc.import" attempts to log at DEBUG
* (let's say), the handler will attempt to match the log domain to
* successively-longer paths: first "", then "gnc", then "gnc.import". Given
* the settings above, the path "gnc" will match -- at a level of "WARN" --
* and the DEBUG-level log will be rejected. When code in the log domain of
* "gnc.ui.plugin-page.sx-list" logs at DEBUG, however, it will match at
* DEBUG, and be allowed.
*
* The current log format is as above:
*
* @verbatim
* [timestamp] [level] <[log-domain]> [message]
@endverbatim
*
* The timestamp and level are constant width (level is 5 characters). The
* log domain is re-iterated, which gives some context, but could become
* annoying if they get long.
*
* Trailing newlines (e.g. <tt>PINFO("...\n", ...)</tt>) are removed; the logger
* will newline separate output.
*
* @section best Best Practices
*
* Code should:
*
* @li Define both <tt>static QofLogModule log_module</tt> and <tt>#define
* G_LOG_DOMAIN</tt> to the same value.
* @li Define a logical, specific path as the log domain;
* @c "gnc.gui.plugin-pages.sx-list" or
* @c "gnc.register.gnome.cell.quickfill" are
* good examples.
* @li Prefer the macros defined here (PERR, PWARN, PINFO, etc.) to
* the GLib-provided functions that they wrap because it allows us to
* more easily replace the GLib logging functinos with another
* implementation and besides our macros are able to short-circuit
* GLib's rather slow domain and level matching.
*
* @see qof_log_parse_log_config(const char*)
**/
#ifndef _QOF_LOG_H
#define _QOF_LOG_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdarg.h>
#include <stdio.h>
#include <glib.h>
#include "qofutil.h"
typedef const gchar* QofLogModule;
#define QOF_MOD_ENGINE "qof.engine"
typedef enum
{
QOF_LOG_FATAL = G_LOG_LEVEL_ERROR,
QOF_LOG_ERROR = G_LOG_LEVEL_CRITICAL,
QOF_LOG_WARNING = G_LOG_LEVEL_WARNING,
QOF_LOG_MESSAGE = G_LOG_LEVEL_MESSAGE,
QOF_LOG_INFO = G_LOG_LEVEL_INFO,
QOF_LOG_DEBUG = G_LOG_LEVEL_DEBUG
} QofLogLevel;
const char* qof_log_level_to_string(QofLogLevel lvl);
QofLogLevel qof_log_level_from_string(const char *str);
/** Indents one level; see ENTER macro. **/
void qof_log_indent(void);
/**
* De-dent one level, capped at 0; see LEAVE macro.
**/
void qof_log_dedent(void);
/**
* Initialize the error logging subsystem. Defaults to a level-threshold of
* "warning", and logging to stderr.
**/
void qof_log_init (void);
/** Set the logging level of the given log_module. **/
void qof_log_set_level(QofLogModule module, QofLogLevel level);
/** Specify an alternate log output, to pipe or file. **/
void qof_log_set_file (FILE *outfile);
/** Specify a filename for log output. **/
void qof_log_init_filename (const gchar* logfilename);
/**
* If @a log_to_filename is "stderr" or "stdout" (exactly,
* case-insensitive), then those special files are used; otherwise, the
* literal filename as given, as qof_log_init_filename(gchar*)
**/
void qof_log_init_filename_special(const char *log_to_filename);
/**
* Parse a log-configuration file. A GKeyFile-format file of the schema:
* @verbatim
[levels]
# log.ger.path=level
gnc.engine.sx=debug
gnc.gui.sx=debug
gnc.import-export.qif.parse=debug
[output]
# to=["stderr"|"stdout"|filename]
to=stderr
@endverbatim
**/
void qof_log_parse_log_config(const char *filename);
/** Be nice, close the logfile if possible. */
void qof_log_shutdown (void);
/**
* Cleans up subroutine names. AIX/xlC has the habit of printing signatures
* not names; clean this up. On other operating systems, truncate name to
* QOF_LOG_MAX_CHARS chars.
**/
const gchar * qof_log_prettify (const gchar *name);
/** Check to see if the given @a log_module is configured to log at the given
* @a log_level. This implements the "log.path.hierarchy" logic. **/
gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level);
#define PRETTY_FUNC_NAME qof_log_prettify(G_STRFUNC)
#ifdef _MSC_VER
/* Microsoft Visual Studio: MSVC compiler has a different syntax for
* macros with variadic argument list. */
/* TODO: After the C++2a feature __VA_OPT__ gets implemented in both
* flavors, it should be inserted before __VA_ARGS__ and the else branch
* gets obsolete and should be removed.
*/
/** Log a fatal error */
#define FATAL(format, ...) do { \
g_log (log_module, G_LOG_LEVEL_ERROR, \
"[%s()] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
} while (0)
/** Log a serious error */
#define PERR(format, ...) do { \
g_log (log_module, G_LOG_LEVEL_CRITICAL, \
"[%s()] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
} while (0)
/** Log a warning */
#define PWARN(format, ...) do { \
g_log (log_module, G_LOG_LEVEL_WARNING, \
"[%s()] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
} while (0)
/** Print an informational note */
#define PINFO(format, ...) \
if (qof_log_check(log_module, QOF_LOG_INFO) { \
g_log (log_module, G_LOG_LEVEL_INFO, \
"[%s] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
}
/** Print a debugging message */
#define DEBUG(format, ...) \
if (qof_log_check(log_module, QOF_LOG_DEBUG) { \
g_log (log_module, G_LOG_LEVEL_DEBUG, \
"[%s] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
}
/** Print a function entry debugging message */
#define ENTER(format, ...) \
if (qof_log_check(log_module, QOFLOG_DEBUG)) { \
g_log (log_module, G_LOG_LEVEL_DEBUG, \
"[enter %s:%s()] " format, __FILE__, \
PRETTY_FUNC_NAME , __VA_ARGS__); \
qof_log_indent(); \
}
/** Print a function exit debugging message. **/
#define LEAVE(format, ...) \
if (qof_log_check(log_module, QOF_LOG_DEBUG)) { \
qof_log_dedent(); \
g_log (log_module, G_LOG_LEVEL_DEBUG, \
"[leave %s()] " format, \
PRETTY_FUNC_NAME , __VA_ARGS__); \
}
#else /* _MSC_VER */
/** Log a fatal error */
#define FATAL(format, args...) do { \
g_log (log_module, G_LOG_LEVEL_ERROR, \
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
} while (0)
/** Log a serious error */
#define PERR(format, args...) do { \
g_log (log_module, G_LOG_LEVEL_CRITICAL, \
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
} while (0)
/** Log a warning */
#define PWARN(format, args...) do { \
g_log (log_module, G_LOG_LEVEL_WARNING, \
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
} while (0)
/** Print an informational note */
#define PINFO(format, args...) do { \
if (qof_log_check(log_module, QOF_LOG_INFO)) { \
g_log (log_module, G_LOG_LEVEL_INFO, \
"[%s] " format, PRETTY_FUNC_NAME , ## args); \
} \
} while (0)
/** Print a debugging message */
#define DEBUG(format, args...) do { \
if (qof_log_check(log_module, QOF_LOG_DEBUG)) { \
g_log (log_module, G_LOG_LEVEL_DEBUG, \
"[%s] " format, PRETTY_FUNC_NAME , ## args); \
} \
} while(0)
/** Print a function entry debugging message */
#define ENTER(format, args...) do { \
if (qof_log_check(log_module, QOF_LOG_DEBUG)) { \
g_log (log_module, G_LOG_LEVEL_DEBUG, \
"[enter %s:%s()] " format, __FILE__, \
PRETTY_FUNC_NAME , ## args); \
qof_log_indent(); \
} \
} while (0)
/** Print a function exit debugging message. **/
#define LEAVE(format, args...) do { \
if (qof_log_check(log_module, QOF_LOG_DEBUG)) { \
qof_log_dedent(); \
g_log (log_module, G_LOG_LEVEL_DEBUG, \
"[leave %s()] " format, \
PRETTY_FUNC_NAME , ## args); \
} \
} while (0)
#endif /* _MSC_VER */
/** Replacement for @c g_return_val_if_fail, but calls LEAVE if the test fails. **/
#define gnc_leave_return_val_if_fail(test, val) do { \
if (! (test)) { LEAVE(""); } \
g_return_val_if_fail(test, val); \
} while (0);
/** Replacement for @c g_return_if_fail, but calls LEAVE if the test fails. **/
#define gnc_leave_return_if_fail(test) do { \
if (! (test)) { LEAVE(""); } \
g_return_if_fail(test); \
} while (0);
#ifdef __cplusplus
}
#endif
#endif /* _QOF_LOG_H */
/** @} */