1 /* qof-log.h
2  * Author: Rob Clark <rclark@cs.hmc.edu>
3  * Copyright (C) 1998-2003 Linas Vepstas <linas@linas.org>
4  * Copyright 2005 Neil Williams <linux@codehelp.co.uk>
5  * Copyright 2007 Joshua Sled <jsled@asynchronous.org>
6  */
7 
8 /*
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  *  02110-1301,  USA
23  */
24 
25 /**
26  * @addtogroup Logging
27  * @{
28  * @ingroup QOF
29  * @brief Logging and tracing facility.
30  * @sa "Logging overhaul" announcement <https://lists.gnucash.org/pipermail/gnucash-devel/2007-February/019836.html>
31  *
32  * qof_log_init(void) installs a handler that interprets the "log_domain"
33  * as a "."-separated path.  Log level thresholds can be set for each level
34  * in the tree.  When a message is logged, the longest level match is
35  * found, and used as the threshold.
36  *
37  * For instance, we can set the levels as such:
38  * @verbatim
39    "qof"                        = WARN
40    "gnc"                        = WARN
41    "gnc.ui"                     = INFO
42    "gnc.ui.plugin-page.sx-list" = DEBUG
43  @endverbatim
44  *
45  * When code in the log_module of "gnc.import" attempts to log at DEBUG
46  * (let's say), the handler will attempt to match the log domain to
47  * successively-longer paths: first "", then "gnc", then "gnc.import".  Given
48  * the settings above, the path "gnc" will match -- at a level of "WARN" --
49  * and the DEBUG-level log will be rejected.  When code in the log domain of
50  * "gnc.ui.plugin-page.sx-list" logs at DEBUG, however, it will match at
51  * DEBUG, and be allowed.
52  *
53  * The current log format is as above:
54  *
55  * @verbatim
56      * [timestamp] [level] <[log-domain]> [message]
57  @endverbatim
58  *
59  * The timestamp and level are constant width (level is 5 characters).  The
60  * log domain is re-iterated, which gives some context, but could become
61  * annoying if they get long.
62  *
63  * Trailing newlines (e.g. <tt>PINFO("...\n", ...)</tt>) are removed; the logger
64  * will newline separate output.
65  *
66  * @section best Best Practices
67  *
68  * Code should:
69  *
70  * @li Define both <tt>static QofLogModule log_module</tt> and <tt>#define
71  *   G_LOG_DOMAIN</tt> to the same value.
72  * @li Define a logical, specific path as the log domain;
73  *   @c "gnc.gui.plugin-pages.sx-list" or
74  *   @c "gnc.register.gnome.cell.quickfill" are
75  *   good examples.
76  * @li Prefer the macros defined here (PERR, PWARN, PINFO, etc.) to
77  *   the GLib-provided functions that they wrap because it allows us to
78  *   more easily replace the GLib logging functinos with another
79  *   implementation and besides our macros are able to short-circuit
80  *   GLib's rather slow domain and level matching.
81  *
82  * @see qof_log_parse_log_config(const char*)
83  **/
84 
85 #ifndef _QOF_LOG_H
86 #define _QOF_LOG_H
87 
88 #ifdef __cplusplus
89 extern "C"
90 {
91 #endif
92 
93 #include <stdarg.h>
94 #include <stdio.h>
95 #include <glib.h>
96 #include "qofutil.h"
97 
98 typedef const gchar* QofLogModule;
99 
100 #define QOF_MOD_ENGINE "qof.engine"
101 
102 typedef enum
103 {
104     QOF_LOG_FATAL   = G_LOG_LEVEL_ERROR,
105     QOF_LOG_ERROR   = G_LOG_LEVEL_CRITICAL,
106     QOF_LOG_WARNING = G_LOG_LEVEL_WARNING,
107     QOF_LOG_MESSAGE = G_LOG_LEVEL_MESSAGE,
108     QOF_LOG_INFO    = G_LOG_LEVEL_INFO,
109     QOF_LOG_DEBUG   = G_LOG_LEVEL_DEBUG
110 } QofLogLevel;
111 
112 const char* qof_log_level_to_string(QofLogLevel lvl);
113 QofLogLevel qof_log_level_from_string(const char *str);
114 
115 /** Indents one level; see ENTER macro. **/
116 void qof_log_indent(void);
117 
118 /**
119  * De-dent one level, capped at 0; see LEAVE macro.
120  **/
121 void qof_log_dedent(void);
122 
123 /**
124  * Initialize the error logging subsystem.  Defaults to a level-threshold of
125  * "warning", and logging to stderr.
126  **/
127 void qof_log_init (void);
128 
129 /** Set the logging level of the given log_module. **/
130 void qof_log_set_level(QofLogModule module, QofLogLevel level);
131 
132 /** Specify an alternate log output, to pipe or file. **/
133 void qof_log_set_file (FILE *outfile);
134 
135 /** Specify a filename for log output. **/
136 void qof_log_init_filename (const gchar* logfilename);
137 
138 /**
139  * If @a log_to_filename is "stderr" or "stdout" (exactly,
140  * case-insensitive), then those special files are used; otherwise, the
141  * literal filename as given, as qof_log_init_filename(gchar*)
142  **/
143 void qof_log_init_filename_special(const char *log_to_filename);
144 
145 /**
146  * Parse a log-configuration file.  A GKeyFile-format file of the schema:
147  * @verbatim
148     [levels]
149     # log.ger.path=level
150     gnc.engine.sx=debug
151     gnc.gui.sx=debug
152     gnc.import-export.qif.parse=debug
153     [output]
154     # to=["stderr"|"stdout"|filename]
155     to=stderr
156  @endverbatim
157  **/
158 void qof_log_parse_log_config(const char *filename);
159 
160 /** Be nice, close the logfile if possible. */
161 void qof_log_shutdown (void);
162 
163 /**
164  * Cleans up subroutine names. AIX/xlC has the habit of printing signatures
165  * not names; clean this up. On other operating systems, truncate name to
166  * QOF_LOG_MAX_CHARS chars.
167  **/
168 const gchar * qof_log_prettify (const gchar *name);
169 
170 /** Check to see if the given @a log_module is configured to log at the given
171  * @a log_level.  This implements the "log.path.hierarchy" logic. **/
172 gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level);
173 
174 #define PRETTY_FUNC_NAME qof_log_prettify(G_STRFUNC)
175 
176 #ifdef _MSC_VER
177 /* Microsoft Visual Studio: MSVC compiler has a different syntax for
178  * macros with variadic argument list. */
179 
180 /* TODO: After the C++2a feature __VA_OPT__ gets implemented in both
181  * flavors, it should be inserted before __VA_ARGS__ and the else branch
182  * gets obsolete and should be removed.
183  */
184 
185 /** Log a fatal error */
186 #define FATAL(format, ...) do { \
187     g_log (log_module, G_LOG_LEVEL_ERROR, \
188       "[%s()] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
189 } while (0)
190 
191 /** Log a serious error */
192 #define PERR(format, ...) do { \
193     g_log (log_module, G_LOG_LEVEL_CRITICAL, \
194       "[%s()] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
195 } while (0)
196 
197 /** Log a warning */
198 #define PWARN(format, ...) do { \
199     g_log (log_module, G_LOG_LEVEL_WARNING, \
200       "[%s()] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
201 } while (0)
202 
203 /** Print an informational note */
204 #define PINFO(format, ...) \
205     if (qof_log_check(log_module, QOF_LOG_INFO) {    \
206     g_log (log_module, G_LOG_LEVEL_INFO, \
207       "[%s] " format, PRETTY_FUNC_NAME , __VA_ARGS__); \
208 }
209 
210 /** Print a debugging message */
211 #define DEBUG(format, ...) \
212     if (qof_log_check(log_module, QOF_LOG_DEBUG) {    \
213         g_log (log_module, G_LOG_LEVEL_DEBUG,                           \
214                "[%s] " format, PRETTY_FUNC_NAME , __VA_ARGS__);         \
215 }
216 
217 /** Print a function entry debugging message */
218 #define ENTER(format, ...) \
219     if (qof_log_check(log_module, QOFLOG_DEBUG)) { \
220       g_log (log_module, G_LOG_LEVEL_DEBUG, \
221         "[enter %s:%s()] " format, __FILE__, \
222         PRETTY_FUNC_NAME , __VA_ARGS__); \
223       qof_log_indent(); \
224 }
225 
226 /** Print a function exit debugging message. **/
227 #define LEAVE(format, ...) \
228     if (qof_log_check(log_module, QOF_LOG_DEBUG)) { \
229       qof_log_dedent(); \
230       g_log (log_module, G_LOG_LEVEL_DEBUG, \
231         "[leave %s()] " format, \
232         PRETTY_FUNC_NAME , __VA_ARGS__); \
233 }
234 
235 #else /* _MSC_VER */
236 
237 /** Log a fatal error */
238 #define FATAL(format, args...) do { \
239     g_log (log_module, G_LOG_LEVEL_ERROR, \
240       "[%s()] " format, PRETTY_FUNC_NAME , ## args); \
241 } while (0)
242 
243 /** Log a serious error */
244 #define PERR(format, args...) do { \
245     g_log (log_module, G_LOG_LEVEL_CRITICAL, \
246       "[%s()] " format, PRETTY_FUNC_NAME , ## args); \
247 } while (0)
248 
249 /** Log a warning */
250 #define PWARN(format, args...) do { \
251     g_log (log_module, G_LOG_LEVEL_WARNING, \
252       "[%s()] " format, PRETTY_FUNC_NAME , ## args); \
253 } while (0)
254 
255 /** Print an informational note */
256 #define PINFO(format, args...) do {                  \
257     if (qof_log_check(log_module, QOF_LOG_INFO)) {   \
258         g_log (log_module, G_LOG_LEVEL_INFO,         \
259                "[%s] " format, PRETTY_FUNC_NAME , ## args);     \
260     } \
261 } while (0)
262 
263 /** Print a debugging message */
264 #define DEBUG(format, args...) do {                      \
265     if (qof_log_check(log_module, QOF_LOG_DEBUG)) {      \
266         g_log (log_module, G_LOG_LEVEL_DEBUG,         \
267                "[%s] " format, PRETTY_FUNC_NAME , ## args);     \
268     } \
269 } while(0)
270 
271 /** Print a function entry debugging message */
272 #define ENTER(format, args...) do {                     \
273     if (qof_log_check(log_module, QOF_LOG_DEBUG)) {     \
274         g_log (log_module, G_LOG_LEVEL_DEBUG,           \
275                "[enter %s:%s()] " format, __FILE__,     \
276                PRETTY_FUNC_NAME , ## args);             \
277         qof_log_indent();                               \
278     } \
279 } while (0)
280 
281 /** Print a function exit debugging message. **/
282 #define LEAVE(format, args...) do {                     \
283     if (qof_log_check(log_module, QOF_LOG_DEBUG)) {     \
284         qof_log_dedent();                               \
285         g_log (log_module, G_LOG_LEVEL_DEBUG,           \
286                "[leave %s()] " format,                  \
287                PRETTY_FUNC_NAME , ## args);             \
288     }                                                   \
289 } while (0)
290 
291 #endif /* _MSC_VER */
292 
293 /** Replacement for @c g_return_val_if_fail, but calls LEAVE if the test fails. **/
294 #define gnc_leave_return_val_if_fail(test, val) do { \
295   if (! (test)) { LEAVE(""); } \
296   g_return_val_if_fail(test, val); \
297 } while (0);
298 
299 /** Replacement for @c g_return_if_fail, but calls LEAVE if the test fails. **/
300 #define gnc_leave_return_if_fail(test) do { \
301   if (! (test)) { LEAVE(""); } \
302   g_return_if_fail(test); \
303 } while (0);
304 
305 
306 #ifdef __cplusplus
307 }
308 #endif
309 
310 #endif /* _QOF_LOG_H */
311 
312 /** @} */
313