GnuCash c935c2f+
Loading...
Searching...
No Matches
Macros | Typedefs | Enumerations | Functions

Logging and tracing facility. More...

Macros

#define QOF_MOD_ENGINE   "qof.engine"
 
#define PRETTY_FUNC_NAME   qof_log_prettify(G_STRFUNC)
 
#define FATAL(format, args...)
 Log a fatal error.
 
#define PERR(format, args...)
 Log a serious error.
 
#define PWARN(format, args...)
 Log a warning.
 
#define PINFO(format, args...)
 Print an informational note.
 
#define DEBUG(format, args...)
 Print a debugging message.
 
#define ENTER(format, args...)
 Print a function entry debugging message.
 
#define LEAVE(format, args...)
 Print a function exit debugging message.
 
#define gnc_leave_return_val_if_fail(test, val)
 Replacement for g_return_val_if_fail, but calls LEAVE if the test fails.
 
#define gnc_leave_return_if_fail(test)
 Replacement for g_return_if_fail, but calls LEAVE if the test fails.
 

Typedefs

typedef const gchar * QofLogModule
 

Enumerations

enum  QofLogLevel {
  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
}
 

Functions

const char * qof_log_level_to_string (QofLogLevel lvl)
 
QofLogLevel qof_log_level_from_string (const char *str)
 
void qof_log_indent (void)
 Indents one level; see ENTER macro.
 
void qof_log_dedent (void)
 De-dent one level, capped at 0; see LEAVE macro.
 
void qof_log_init (void)
 Initialize the error logging subsystem.
 
void qof_log_set_level (QofLogModule module, QofLogLevel level)
 Set the logging level of the given log_module.
 
void qof_log_set_file (FILE *outfile)
 Specify an alternate log output, to pipe or file.
 
void qof_log_init_filename (const gchar *logfilename)
 Specify a filename for log output.
 
void qof_log_init_filename_special (const char *log_to_filename)
 If 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_parse_log_config (const char *filename)
 Parse a log-configuration file.
 
void qof_log_shutdown (void)
 Be nice, close the logfile if possible.
 
const gchar * qof_log_prettify (const gchar *name)
 Cleans up subroutine names.
 
gboolean qof_log_check (QofLogModule log_module, QofLogLevel log_level)
 Check to see if the given log_module is configured to log at the given log_level.
 

Detailed Description

Logging and tracing facility.

See also
"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:

  "qof"                        = WARN
  "gnc"                        = WARN
  "gnc.ui"                     = INFO
  "gnc.ui.plugin-page.sx-list" = DEBUG

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:

    * [timestamp] [level] <[log-domain]> [message]

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. PINFO("...\n", ...)) are removed; the logger will newline separate output.

Best Practices

Code should:

See also
qof_log_parse_log_config(const char*)

Macro Definition Documentation

◆ DEBUG

#define DEBUG (   format,
  args... 
)
Value:
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)
gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level)
Check to see if the given log_module is configured to log at the given log_level.
Definition qoflog.cpp:330

Print a debugging message.

Definition at line 264 of file qoflog.h.

264 { \
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)

◆ ENTER

#define ENTER (   format,
  args... 
)
Value:
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 entry debugging message.

Definition at line 272 of file qoflog.h.

272 { \
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)

◆ FATAL

#define FATAL (   format,
  args... 
)
Value:
do { \
g_log (log_module, G_LOG_LEVEL_ERROR, \
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
} while (0)

Log a fatal error.

Definition at line 238 of file qoflog.h.

238 { \
239 g_log (log_module, G_LOG_LEVEL_ERROR, \
240 "[%s()] " format, PRETTY_FUNC_NAME , ## args); \
241} while (0)

◆ gnc_leave_return_if_fail

#define gnc_leave_return_if_fail (   test)
Value:
do { \
if (! (test)) { LEAVE(""); } \
g_return_if_fail(test); \
} while (0);
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282

Replacement for g_return_if_fail, but calls LEAVE if the test fails.

Definition at line 300 of file qoflog.h.

300 { \
301 if (! (test)) { LEAVE(""); } \
302 g_return_if_fail(test); \
303} while (0);

◆ gnc_leave_return_val_if_fail

#define gnc_leave_return_val_if_fail (   test,
  val 
)
Value:
do { \
if (! (test)) { LEAVE(""); } \
g_return_val_if_fail(test, val); \
} while (0);

Replacement for g_return_val_if_fail, but calls LEAVE if the test fails.

Definition at line 294 of file qoflog.h.

294 { \
295 if (! (test)) { LEAVE(""); } \
296 g_return_val_if_fail(test, val); \
297} while (0);

◆ LEAVE

#define LEAVE (   format,
  args... 
)
Value:
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)

Print a function exit debugging message.

Definition at line 282 of file qoflog.h.

282 { \
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)

◆ PERR

#define PERR (   format,
  args... 
)
Value:
do { \
g_log (log_module, G_LOG_LEVEL_CRITICAL, \
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
} while (0)

Log a serious error.

Definition at line 244 of file qoflog.h.

244 { \
245 g_log (log_module, G_LOG_LEVEL_CRITICAL, \
246 "[%s()] " format, PRETTY_FUNC_NAME , ## args); \
247} while (0)

◆ PINFO

#define PINFO (   format,
  args... 
)
Value:
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 an informational note.

Definition at line 256 of file qoflog.h.

256 { \
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)

◆ PRETTY_FUNC_NAME

#define PRETTY_FUNC_NAME   qof_log_prettify(G_STRFUNC)

Definition at line 174 of file qoflog.h.

◆ PWARN

#define PWARN (   format,
  args... 
)
Value:
do { \
g_log (log_module, G_LOG_LEVEL_WARNING, \
"[%s()] " format, PRETTY_FUNC_NAME , ## args); \
} while (0)

Log a warning.

Definition at line 250 of file qoflog.h.

250 { \
251 g_log (log_module, G_LOG_LEVEL_WARNING, \
252 "[%s()] " format, PRETTY_FUNC_NAME , ## args); \
253} while (0)

◆ QOF_MOD_ENGINE

#define QOF_MOD_ENGINE   "qof.engine"

Definition at line 100 of file qoflog.h.

Typedef Documentation

◆ QofLogModule

typedef const gchar* QofLogModule

Definition at line 98 of file qoflog.h.

Enumeration Type Documentation

◆ QofLogLevel

enum QofLogLevel

Definition at line 102 of file qoflog.h.

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;

Function Documentation

◆ qof_log_check()

gboolean qof_log_check ( QofLogModule  log_module,
QofLogLevel  log_level 
)

Check to see if the given log_module is configured to log at the given log_level.

This implements the "log.path.hierarchy" logic.

Definition at line 330 of file qoflog.cpp.

331{
332// Check the global levels
333 if (level > current_max)
334 return FALSE;
335 if (level <= default_level)
336 return TRUE;
337 auto module = get_modules();
338 // If the level <= the default then no need to look further.
339 if (level <= module->m_level)
340 return TRUE;
341
342 if (!domain)
343 return FALSE;
344
345 auto domain_vec = split_domain(domain);
346
347 for (const auto& part : domain_vec)
348 {
349 auto iter = std::find_if(module->m_children.begin(),
350 module->m_children.end(),
351 [part](auto& child) {
352 return child && part == child->m_name; });
353
354 if (iter == module->m_children.end())
355 return FALSE;
356
357 if (level <= (*iter)->m_level)
358 return TRUE;
359
360 module = iter->get();
361 }
362 return FALSE;
363}

◆ qof_log_dedent()

void qof_log_dedent ( void  )

De-dent one level, capped at 0; see LEAVE macro.

Definition at line 136 of file qoflog.cpp.

137{
138 qof_log_num_spaces
139 = (qof_log_num_spaces < QOF_LOG_INDENT_WIDTH)
140 ? 0
141 : qof_log_num_spaces - QOF_LOG_INDENT_WIDTH;
142}

◆ qof_log_indent()

void qof_log_indent ( void  )

Indents one level; see ENTER macro.

Definition at line 130 of file qoflog.cpp.

131{
132 qof_log_num_spaces += QOF_LOG_INDENT_WIDTH;
133}

◆ qof_log_init()

void qof_log_init ( void  )

Initialize the error logging subsystem.

Defaults to a level-threshold of "warning", and logging to stderr.

Definition at line 156 of file qoflog.cpp.

157{
158 qof_log_init_filename(nullptr);
159}
void qof_log_init_filename(const gchar *log_filename)
Specify a filename for log output.
Definition qoflog.cpp:207

◆ qof_log_init_filename()

void qof_log_init_filename ( const gchar *  logfilename)

Specify a filename for log output.

Definition at line 207 of file qoflog.cpp.

208{
209 gboolean warn_about_missing_permission = FALSE;
210 auto modules = get_modules();
211
212 if (!qof_logger_format)
213 qof_logger_format = g_strdup ("* %s %*s <%s> %*s%s%s"); //default format
214
215 if (log_filename)
216 {
217 int fd;
218 gchar *fname;
219
220 if (fout != nullptr && fout != stderr && fout != stdout)
221 fclose(fout);
222
223 fname = g_strconcat(log_filename, ".XXXXXX.log", nullptr);
224
225 if ((fd = g_mkstemp(fname)) != -1)
226 {
227#if PLATFORM(WINDOWS)
228 /* MSVC compiler: Somehow the OS thinks file descriptor from above
229 * still isn't open. So we open normally with the file name and that's it. */
230 fout = g_fopen(fname, "wb");
231#else
232 /* We must not overwrite /dev/null */
233 g_assert(g_strcmp0(log_filename, "/dev/null") != 0);
234
235 /* Windows prevents renaming of open files, so the next command silently fails there
236 * No problem, the filename on Windows will simply have the random characters */
237 g_rename(fname, log_filename);
238 fout = fdopen(fd, "w");
239#endif
240 if (!fout)
241 warn_about_missing_permission = TRUE;
242 }
243 else
244 {
245 warn_about_missing_permission = TRUE;
246 fout = stderr;
247 }
248 g_free(fname);
249 }
250
251 if (!fout)
252 fout = stderr;
253
254 if (previous_handler == nullptr)
255 previous_handler = g_log_set_default_handler(log4glib_handler, modules);
256
257 if (warn_about_missing_permission)
258 {
259 g_critical("Cannot open log output file \"%s\", using stderr.", log_filename);
260 }
261}

◆ qof_log_init_filename_special()

void qof_log_init_filename_special ( const char *  log_to_filename)

If 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*)

Definition at line 402 of file qoflog.cpp.

403{
404 if (g_ascii_strcasecmp("stderr", log_to_filename) == 0)
405 {
406 qof_log_init();
407 qof_log_set_file(stderr);
408 }
409 else if (g_ascii_strcasecmp("stdout", log_to_filename) == 0)
410 {
411 qof_log_init();
412 qof_log_set_file(stdout);
413 }
414 else
415 {
416 qof_log_init_filename(log_to_filename);
417 }
418}
void qof_log_init(void)
Initialize the error logging subsystem.
Definition qoflog.cpp:156
void qof_log_set_file(FILE *outfile)
Specify an alternate log output, to pipe or file.
Definition qoflog.cpp:145

◆ qof_log_level_to_string()

const char * qof_log_level_to_string ( QofLogLevel  lvl)

Definition at line 501 of file qoflog.cpp.

502{
503 const char *level_str;
504 switch (log_level)
505 {
506 case QOF_LOG_FATAL:
507 level_str = "FATAL";
508 break;
509 case QOF_LOG_ERROR:
510 level_str = "ERROR";
511 break;
512 case QOF_LOG_WARNING:
513 level_str = "WARN";
514 break;
515 case QOF_LOG_MESSAGE:
516 level_str = "MESSG";
517 break;
518 case QOF_LOG_INFO:
519 level_str = "INFO";
520 break;
521 case QOF_LOG_DEBUG:
522 level_str = "DEBUG";
523 break;
524 default:
525 level_str = "OTHER";
526 break;
527 }
528 return level_str;
529}

◆ qof_log_parse_log_config()

void qof_log_parse_log_config ( const char *  filename)

Parse a log-configuration file.

A GKeyFile-format file of the schema:

   [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

Definition at line 421 of file qoflog.cpp.

422{
423 const gchar *levels_group = "levels", *output_group = "output";
424 GError *err = nullptr;
425 GKeyFile *conf = g_key_file_new();
426
427 if (!g_key_file_load_from_file(conf, filename, G_KEY_FILE_NONE, &err))
428 {
429 g_warning("unable to parse [%s]: %s", filename, err->message);
430 g_error_free(err);
431 return;
432 }
433
434 DEBUG("parsing log config from [%s]", filename);
435 if (g_key_file_has_group(conf, levels_group))
436 {
437 gsize num_levels;
438 unsigned int key_idx;
439 gchar **levels;
440 gint logger_max_name_length = 12;
441 gchar *str = nullptr;
442
443 levels = g_key_file_get_keys(conf, levels_group, &num_levels, nullptr);
444
445 for (key_idx = 0; key_idx < num_levels && levels[key_idx] != nullptr; key_idx++)
446 {
447 QofLogLevel level;
448 gchar *logger_name = nullptr, *level_str = nullptr;
449
450 logger_name = g_strdup(levels[key_idx]);
451 logger_max_name_length = MAX (logger_max_name_length, (gint) strlen (logger_name));
452 level_str = g_key_file_get_string(conf, levels_group, logger_name, nullptr);
453 level = qof_log_level_from_string(level_str);
454
455 DEBUG("setting log [%s] to level [%s=%d]", logger_name, level_str, level);
456 qof_log_set_level(logger_name, level);
457
458 g_free(logger_name);
459 g_free(level_str);
460 }
461
462 str = g_strdup_printf ("%d", logger_max_name_length);
463 if (qof_logger_format)
464 g_free (qof_logger_format);
465 qof_logger_format = g_strconcat ("* %s %*s <%-", str, ".", str, "s> %*s%s%s", nullptr);
466
467 g_free (str);
468 g_strfreev(levels);
469 }
470
471 if (g_key_file_has_group(conf, output_group))
472 {
473 gsize num_outputs;
474 unsigned int output_idx;
475 gchar **outputs;
476
477 outputs = g_key_file_get_keys(conf, output_group, &num_outputs, nullptr);
478 for (output_idx = 0; output_idx < num_outputs && outputs[output_idx] != nullptr; output_idx++)
479 {
480 gchar *key = outputs[output_idx];
481 gchar *value;
482
483 if (g_ascii_strcasecmp("to", key) != 0)
484 {
485 g_warning("unknown key [%s] in [outputs], skipping", key);
486 continue;
487 }
488
489 value = g_key_file_get_string(conf, output_group, key, nullptr);
490 DEBUG("setting [output].to=[%s]", value);
492 g_free(value);
493 }
494 g_strfreev(outputs);
495 }
496
497 g_key_file_free(conf);
498}
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
void qof_log_set_level(QofLogModule log_module, QofLogLevel level)
Set the logging level of the given log_module.
Definition qoflog.cpp:297
void qof_log_init_filename_special(const char *log_to_filename)
If log_to_filename is "stderr" or "stdout" (exactly, case-insensitive), then those special files are ...
Definition qoflog.cpp:402

◆ qof_log_prettify()

const gchar * qof_log_prettify ( const gchar *  name)

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.

◆ qof_log_set_file()

void qof_log_set_file ( FILE *  outfile)

Specify an alternate log output, to pipe or file.

Definition at line 145 of file qoflog.cpp.

146{
147 if (!outfile)
148 {
149 fout = stderr;
150 return;
151 }
152 fout = outfile;
153}

◆ qof_log_set_level()

void qof_log_set_level ( QofLogModule  module,
QofLogLevel  level 
)

Set the logging level of the given log_module.

Definition at line 297 of file qoflog.cpp.

298{
299 if (!log_module || level == QOF_LOG_FATAL)
300 return;
301
302 if (level > current_max)
303 current_max = level;
304
305 auto module_parts = split_domain(log_module);
306 auto module = get_modules();
307 for (auto part : module_parts)
308 {
309 auto iter = std::find_if(module->m_children.begin(),
310 module->m_children.end(),
311 [part](auto& child){
312 return child && part == child->m_name;
313 });
314 if (iter == module->m_children.end())
315 {
316 auto child = std::make_unique<ModuleEntry>(part, default_level);
317 module->m_children.emplace_back(std::move(child));
318 module = module->m_children.back().get();
319 }
320 else
321 {
322 module = iter->get();
323 }
324 }
325 module->m_level = level;
326}

◆ qof_log_shutdown()

void qof_log_shutdown ( void  )

Be nice, close the logfile if possible.

Definition at line 264 of file qoflog.cpp.

265{
266 if (fout && fout != stderr && fout != stdout)
267 {
268 fclose(fout);
269 fout = nullptr;
270 }
271
272 if (qof_logger_format)
273 {
274 g_free (qof_logger_format);
275 qof_logger_format = nullptr;
276 }
277
278 if (function_buffer)
279 {
280 g_free(function_buffer);
281 function_buffer = nullptr;
282 }
283
284 if (_modules != nullptr)
285 {
286 _modules = nullptr;
287 }
288
289 if (previous_handler != nullptr)
290 {
291 g_log_set_default_handler(previous_handler, nullptr);
292 previous_handler = nullptr;
293 }
294}