2007-02-13 18:59:40 -06:00
|
|
|
/* 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>
|
|
|
|
*/
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/**
|
|
|
|
* @addtogroup Logging
|
|
|
|
* @{
|
|
|
|
* @ingroup QOF
|
|
|
|
* @brief Logging and tracing facility.
|
|
|
|
* @sa "Logging overhaul" announcement <http://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.
|
|
|
|
*
|
2007-02-13 19:34:02 -06:00
|
|
|
* @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 Use glib-provided @c g_debug(...), @c g_message(...),
|
|
|
|
* @c g_warning(...), @c g_critical(...) and
|
|
|
|
* @c g_error(...) functions in preference to the historical qof/gnc @c
|
|
|
|
* PINFO, @c PERR (&c.) macros
|
|
|
|
*
|
2007-02-13 18:59:40 -06:00
|
|
|
* @see qof_log_parse_log_config(const char*)
|
|
|
|
**/
|
2006-01-08 11:51:29 -06:00
|
|
|
|
|
|
|
#ifndef _QOF_LOG_H
|
|
|
|
#define _QOF_LOG_H
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
2007-02-09 11:35:00 -06:00
|
|
|
#include <glib.h>
|
2006-04-07 13:50:08 -05:00
|
|
|
#include "qofutil.h"
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2007-02-09 11:35:00 -06:00
|
|
|
#define QOF_MOD_ENGINE "qof.engine"
|
2006-01-08 11:51:29 -06:00
|
|
|
|
|
|
|
#define LOG_LEVEL_LIST(_) \
|
2007-02-09 11:35:00 -06:00
|
|
|
_(QOF_LOG_FATAL, = G_LOG_LEVEL_ERROR) \
|
|
|
|
_(QOF_LOG_ERROR, = G_LOG_LEVEL_CRITICAL) \
|
|
|
|
_(QOF_LOG_WARNING, = G_LOG_LEVEL_WARNING) \
|
|
|
|
_(QOF_LOG_INFO, = G_LOG_LEVEL_INFO) \
|
2007-02-09 15:52:09 -06:00
|
|
|
_(QOF_LOG_DEBUG, = G_LOG_LEVEL_DEBUG)
|
2006-01-08 11:51:29 -06:00
|
|
|
|
|
|
|
DEFINE_ENUM (QofLogLevel, LOG_LEVEL_LIST)
|
|
|
|
|
2007-02-09 11:35:00 -06:00
|
|
|
gchar* qof_log_level_to_string(QofLogLevel lvl);
|
2007-12-29 13:40:28 -06:00
|
|
|
QofLogLevel qof_log_level_from_string(const gchar *str);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** Indents one level; see ENTER macro. **/
|
2007-02-09 15:52:09 -06:00
|
|
|
void qof_log_indent(void);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2007-02-09 11:35:00 -06:00
|
|
|
/**
|
2007-02-13 18:59:40 -06:00
|
|
|
* De-dent one level, capped at 0; see LEAVE macro.
|
2007-02-09 11:35:00 -06:00
|
|
|
**/
|
2007-02-09 15:52:09 -06:00
|
|
|
void qof_log_dedent(void);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2007-02-09 11:35:00 -06:00
|
|
|
/**
|
|
|
|
* Initialize the error logging subsystem. Defaults to a level-threshold of
|
|
|
|
* "warning", and logging to stderr.
|
|
|
|
**/
|
2006-01-08 11:51:29 -06:00
|
|
|
void qof_log_init (void);
|
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** Set the logging level of the given log_module. **/
|
2006-01-08 11:51:29 -06:00
|
|
|
void qof_log_set_level(QofLogModule module, QofLogLevel level);
|
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** Specify an alternate log output, to pipe or file. **/
|
2006-01-08 11:51:29 -06:00
|
|
|
void qof_log_set_file (FILE *outfile);
|
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** Specify a filename for log output. **/
|
2006-01-08 11:51:29 -06:00
|
|
|
void qof_log_init_filename (const gchar* logfilename);
|
|
|
|
|
2007-02-09 19:29:29 -06:00
|
|
|
/**
|
2007-02-13 18:59:40 -06:00
|
|
|
* If @a log_to_filename is "stderr" or "stdout" (exactly,
|
2007-02-09 19:29:29 -06:00
|
|
|
* case-insensitive), then those special files are used; otherwise, the
|
2007-02-13 18:59:40 -06:00
|
|
|
* literal filename as given, as qof_log_init_filename(gchar*)
|
2007-02-09 19:29:29 -06:00
|
|
|
**/
|
|
|
|
void qof_log_init_filename_special(const char *log_to_filename);
|
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/**
|
|
|
|
* 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
|
2007-08-05 16:24:16 -05:00
|
|
|
gnc.import-export.qif.parse=debug
|
2007-02-13 18:59:40 -06:00
|
|
|
[output]
|
|
|
|
# to=["stderr"|"stdout"|filename]
|
|
|
|
to=stderr
|
|
|
|
@endverbatim
|
2007-02-09 19:29:29 -06:00
|
|
|
**/
|
|
|
|
void qof_log_parse_log_config(const char *filename);
|
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/** Be nice, close the logfile if possible. */
|
|
|
|
void qof_log_shutdown (void);
|
|
|
|
|
2007-02-09 11:35:00 -06:00
|
|
|
/**
|
2007-02-13 18:59:40 -06:00
|
|
|
* 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.
|
2007-02-09 11:35:00 -06:00
|
|
|
**/
|
2006-04-07 13:50:08 -05:00
|
|
|
const gchar * qof_log_prettify (const gchar *name);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** 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. **/
|
2006-01-08 11:51:29 -06:00
|
|
|
gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level);
|
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** Set the default level for QOF-related log paths. **/
|
2006-01-08 11:51:29 -06:00
|
|
|
void qof_log_set_default(QofLogLevel log_level);
|
|
|
|
|
2007-02-09 11:35:00 -06:00
|
|
|
#define PRETTY_FUNC_NAME qof_log_prettify(__FUNCTION__)
|
2006-01-08 11:51:29 -06:00
|
|
|
|
|
|
|
/** Log a fatal error */
|
2007-02-09 11:35:00 -06:00
|
|
|
#define FATAL(format, args...) do { \
|
|
|
|
g_log (log_module, G_LOG_LEVEL_FATAL, \
|
|
|
|
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/** Log a serious error */
|
2007-02-09 11:35:00 -06:00
|
|
|
#define PERR(format, args...) do { \
|
|
|
|
g_log (log_module, G_LOG_LEVEL_CRITICAL, \
|
|
|
|
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/** Log a warning */
|
2007-02-09 11:35:00 -06:00
|
|
|
#define PWARN(format, args...) do { \
|
|
|
|
g_log (log_module, G_LOG_LEVEL_WARNING, \
|
|
|
|
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/** Print an informational note */
|
2007-02-09 11:35:00 -06:00
|
|
|
#define PINFO(format, args...) do { \
|
|
|
|
g_log (log_module, G_LOG_LEVEL_INFO, \
|
|
|
|
"[%s] " format, PRETTY_FUNC_NAME , ## args); \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/** Print a debugging message */
|
2007-02-09 11:35:00 -06:00
|
|
|
#define DEBUG(format, args...) do { \
|
|
|
|
g_log (log_module, G_LOG_LEVEL_DEBUG, \
|
|
|
|
"[%s] " format, PRETTY_FUNC_NAME , ## args); \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/** Print a function entry debugging message */
|
2007-02-09 11:35:00 -06:00
|
|
|
#define ENTER(format, args...) do { \
|
2007-02-09 15:52:09 -06:00
|
|
|
if (qof_log_check(log_module, G_LOG_LEVEL_DEBUG)) { \
|
|
|
|
g_log (log_module, G_LOG_LEVEL_DEBUG, \
|
|
|
|
"[enter %s:%s()] " format, __FILE__, \
|
|
|
|
PRETTY_FUNC_NAME , ## args); \
|
|
|
|
qof_log_indent(); \
|
|
|
|
} \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** Replacement for @c g_return_val_if_fail, but calls LEAVE if the test fails. **/
|
2007-02-09 15:52:09 -06:00
|
|
|
#define gnc_leave_return_val_if_fail(test, val) do { \
|
|
|
|
if (! (test)) { LEAVE(""); } \
|
|
|
|
g_return_val_if_fail(test, val); \
|
|
|
|
} while (0);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** Replacement for @c g_return_if_fail, but calls LEAVE if the test fails. **/
|
2007-02-09 15:52:09 -06:00
|
|
|
#define gnc_leave_return_if_fail(test) do { \
|
|
|
|
if (! (test)) { LEAVE(""); } \
|
|
|
|
g_return_if_fail(test); \
|
|
|
|
} while (0);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2007-02-13 18:59:40 -06:00
|
|
|
/** Print a function exit debugging message. **/
|
2007-02-09 15:52:09 -06:00
|
|
|
#define LEAVE(format, args...) do { \
|
|
|
|
if (qof_log_check(log_module, G_LOG_LEVEL_DEBUG)) { \
|
|
|
|
qof_log_dedent(); \
|
|
|
|
g_log (log_module, G_LOG_LEVEL_DEBUG, \
|
|
|
|
"[leave %s()] " format, \
|
|
|
|
PRETTY_FUNC_NAME , ## args); \
|
|
|
|
} \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* -------------------------------------------------------- */
|
2007-02-09 11:35:00 -06:00
|
|
|
|
2006-01-08 11:51:29 -06:00
|
|
|
/** Infrastructure to make timing measurements for critical pieces
|
|
|
|
* of code. Used for only for performance tuning & debugging.
|
|
|
|
*/
|
|
|
|
|
2006-04-07 13:50:08 -05:00
|
|
|
void qof_start_clock (gint clockno, QofLogModule log_module, QofLogLevel log_level,
|
|
|
|
const gchar *function_name, const gchar *format, ...);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2006-04-07 13:50:08 -05:00
|
|
|
void qof_report_clock (gint clockno,
|
2006-01-08 11:51:29 -06:00
|
|
|
QofLogModule log_module,
|
|
|
|
QofLogLevel log_level,
|
2006-04-07 13:50:08 -05:00
|
|
|
const gchar *function_name,
|
|
|
|
const gchar *format, ...);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
2006-04-07 13:50:08 -05:00
|
|
|
void qof_report_clock_total (gint clockno,
|
2006-01-08 11:51:29 -06:00
|
|
|
QofLogModule log_module,
|
|
|
|
QofLogLevel log_level,
|
2006-04-07 13:50:08 -05:00
|
|
|
const gchar *function_name,
|
|
|
|
const gchar *format, ...);
|
2006-01-08 11:51:29 -06:00
|
|
|
|
|
|
|
/** start a particular timer */
|
|
|
|
#define START_CLOCK(clockno,format, args...) do { \
|
2006-03-08 21:48:49 -06:00
|
|
|
if (qof_log_check (log_module, QOF_LOG_INFO)) \
|
|
|
|
qof_start_clock (clockno, log_module, QOF_LOG_INFO, \
|
2006-02-19 16:54:39 -06:00
|
|
|
__FUNCTION__, format , ## args); \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/** report elapsed time since last report on a particular timer */
|
|
|
|
#define REPORT_CLOCK(clockno,format, args...) do { \
|
2006-03-08 21:48:49 -06:00
|
|
|
if (qof_log_check (log_module, QOF_LOG_INFO)) \
|
|
|
|
qof_report_clock (clockno, log_module, QOF_LOG_INFO, \
|
2006-02-19 16:54:39 -06:00
|
|
|
__FUNCTION__, format , ## args); \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/** report total elapsed time since timer started */
|
|
|
|
#define REPORT_CLOCK_TOTAL(clockno,format, args...) do { \
|
2006-03-08 21:48:49 -06:00
|
|
|
if (qof_log_check (log_module, QOF_LOG_INFO)) \
|
|
|
|
qof_report_clock_total (clockno, log_module, QOF_LOG_INFO, \
|
2006-02-19 16:54:39 -06:00
|
|
|
__FUNCTION__, format , ## args); \
|
2006-01-08 11:51:29 -06:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* _QOF_LOG_H */
|
|
|
|
|
|
|
|
/** @} */
|