Logging and tracing facility.
More...
|
#define | QOF_MOD_ENGINE "qof.engine" |
|
#define | PRETTY_FUNC_NAME qof_log_prettify(G_STRFUNC) |
|
#define | FATAL(format, args...) |
| Log a fatal error. More...
|
|
#define | PERR(format, args...) |
| Log a serious error. More...
|
|
#define | PWARN(format, args...) |
| Log a warning. More...
|
|
#define | PINFO(format, args...) |
| Print an informational note. More...
|
|
#define | DEBUG(format, args...) |
| Print a debugging message. More...
|
|
#define | ENTER(format, args...) |
| Print a function entry debugging message. More...
|
|
#define | LEAVE(format, args...) |
| Print a function exit debugging message. More...
|
|
#define | gnc_leave_return_val_if_fail(test, val) |
| Replacement for g_return_val_if_fail , but calls LEAVE if the test fails. More...
|
|
#define | gnc_leave_return_if_fail(test) |
| Replacement for g_return_if_fail , but calls LEAVE if the test fails. More...
|
|
|
typedef const gchar * | QofLogModule |
|
|
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
} |
|
|
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. More...
|
|
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. More...
|
|
void | qof_log_set_level (QofLogModule module, QofLogLevel level) |
| Set the logging level of the given log_module. More...
|
|
void | qof_log_set_file (FILE *outfile) |
| Specify an alternate log output, to pipe or file. More...
|
|
void | qof_log_init_filename (const gchar *logfilename) |
| Specify a filename for log output. More...
|
|
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. More...
|
|
void | qof_log_shutdown (void) |
| Be nice, close the logfile if possible. More...
|
|
const gchar * | qof_log_prettify (const gchar *name) |
| Cleans up subroutine names. More...
|
|
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. More...
|
|
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:
- Define both
static QofLogModule log_module
and #define G_LOG_DOMAIN
to the same value.
- Define a logical, specific path as the log domain;
"gnc.gui.plugin-pages.sx-list"
or "gnc.register.gnome.cell.quickfill"
are good examples.
- 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 also
- qof_log_parse_log_config(const char*)
◆ DEBUG
#define DEBUG |
( |
|
format, |
|
|
|
args... |
|
) |
| |
Value:do { \
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. ...
Print a debugging message.
Definition at line 264 of file qoflog.h.
◆ ENTER
#define ENTER |
( |
|
format, |
|
|
|
args... |
|
) |
| |
Value:do { \
g_log (log_module, G_LOG_LEVEL_DEBUG, \
"[enter %s:%s()] " format, __FILE__, \
PRETTY_FUNC_NAME , ## args); \
qof_log_indent(); \
} \
} 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. ...
Print a function entry debugging message.
Definition at line 272 of file qoflog.h.
◆ 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.
◆ 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.
Replacement for g_return_if_fail
, but calls LEAVE if the test fails.
Definition at line 300 of file qoflog.h.
◆ 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);
#define LEAVE(format, args...)
Print a function exit debugging message.
Replacement for g_return_val_if_fail
, but calls LEAVE if the test fails.
Definition at line 294 of file qoflog.h.
◆ LEAVE
#define LEAVE |
( |
|
format, |
|
|
|
args... |
|
) |
| |
Value:do { \
qof_log_dedent(); \
g_log (log_module, G_LOG_LEVEL_DEBUG, \
"[leave %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. ...
Print a function exit debugging message.
Definition at line 282 of file qoflog.h.
◆ 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.
◆ PINFO
#define PINFO |
( |
|
format, |
|
|
|
args... |
|
) |
| |
Value:do { \
g_log (log_module, G_LOG_LEVEL_INFO, \
"[%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. ...
Print an informational note.
Definition at line 256 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.
◆ 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 328 of file qoflog.cpp.
331 if (level > current_max)
333 if (level <= default_level)
335 auto module = get_modules();
337 if (level <= module->m_level)
343 auto domain_vec = split_domain(domain);
345 for (
auto part : domain_vec)
347 auto iter = std::find_if(module->m_children.begin(),
348 module->m_children.end(),
349 [part](
auto& child) {
350 return child && part == child->m_name; });
352 if (iter == module->m_children.end())
355 if (level <= (*iter)->m_level)
358 module = iter->get();
◆ qof_log_indent()
void qof_log_indent |
( |
void |
| ) |
|
Indents one level; see ENTER macro.
Definition at line 134 of file qoflog.cpp.
136 qof_log_num_spaces += QOF_LOG_INDENT_WIDTH;
◆ 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 160 of file qoflog.cpp.
void qof_log_init_filename(const gchar *log_filename)
Specify a filename for log output.
◆ qof_log_init_filename()
void qof_log_init_filename |
( |
const gchar * |
logfilename | ) |
|
Specify a filename for log output.
Definition at line 211 of file qoflog.cpp.
213 gboolean warn_about_missing_permission = FALSE;
214 auto modules = get_modules();
216 if (!qof_logger_format)
217 qof_logger_format = g_strdup (
"* %s %*s <%s> %*s%s%s");
224 if (fout != NULL && fout != stderr && fout != stdout)
227 fname = g_strconcat(log_filename,
".XXXXXX.log",
nullptr);
229 if ((fd = g_mkstemp(fname)) != -1)
231 #if PLATFORM(WINDOWS) 234 fout = g_fopen(fname,
"wb");
237 g_assert(g_strcmp0(log_filename,
"/dev/null") != 0);
241 g_rename(fname, log_filename);
242 fout = fdopen(fd,
"w");
245 warn_about_missing_permission = TRUE;
249 warn_about_missing_permission = TRUE;
258 if (previous_handler == NULL)
259 previous_handler = g_log_set_default_handler(log4glib_handler, modules);
261 if (warn_about_missing_permission)
263 g_critical(
"Cannot open log output file \"%s\", using stderr.", log_filename);
◆ 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 419 of file qoflog.cpp.
421 const gchar *levels_group =
"levels", *output_group =
"output";
423 GKeyFile *conf = g_key_file_new();
425 if (!g_key_file_load_from_file(conf, filename, G_KEY_FILE_NONE, &err))
427 g_warning(
"unable to parse [%s]: %s", filename, err->message);
432 DEBUG(
"parsing log config from [%s]", filename);
433 if (g_key_file_has_group(conf, levels_group))
436 unsigned int key_idx;
438 gint logger_max_name_length = 12;
441 levels = g_key_file_get_keys(conf, levels_group, &num_levels, NULL);
443 for (key_idx = 0; key_idx < num_levels && levels[key_idx] != NULL; key_idx++)
446 gchar *logger_name = NULL, *level_str = NULL;
448 logger_name = g_strdup(levels[key_idx]);
449 logger_max_name_length = MAX (logger_max_name_length, (gint) strlen (logger_name));
450 level_str = g_key_file_get_string(conf, levels_group, logger_name, NULL);
451 level = qof_log_level_from_string(level_str);
453 DEBUG(
"setting log [%s] to level [%s=%d]", logger_name, level_str, level);
460 str = g_strdup_printf (
"%d", logger_max_name_length);
461 if (qof_logger_format)
462 g_free (qof_logger_format);
463 qof_logger_format = g_strconcat (
"* %s %*s <%-", str,
".", str,
"s> %*s%s%s",
nullptr);
469 if (g_key_file_has_group(conf, output_group))
472 unsigned int output_idx;
475 outputs = g_key_file_get_keys(conf, output_group, &num_outputs, NULL);
476 for (output_idx = 0; output_idx < num_outputs && outputs[output_idx] != NULL; output_idx++)
478 gchar *key = outputs[output_idx];
481 if (g_ascii_strcasecmp(
"to", key) != 0)
483 g_warning(
"unknown key [%s] in [outputs], skipping", key);
487 value = g_key_file_get_string(conf, output_group, key, NULL);
488 DEBUG(
"setting [output].to=[%s]", value);
495 g_key_file_free(conf);
void qof_log_set_level(QofLogModule log_module, QofLogLevel level)
Set the logging level of the given log_module.
#define DEBUG(format, args...)
Print a debugging message.
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 ...
◆ 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 149 of file qoflog.cpp.
◆ 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 295 of file qoflog.cpp.
297 if (!log_module || level == QOF_LOG_FATAL)
300 if (level > current_max)
303 auto module_parts = split_domain(log_module);
304 auto module = get_modules();
305 for (
auto part : module_parts)
307 auto iter = std::find_if(module->m_children.begin(),
308 module->m_children.end(),
310 return child && part == child->m_name;
312 if (iter == module->m_children.end())
314 auto child = std::make_unique<ModuleEntry>(part, default_level);
315 module->m_children.emplace_back(std::move(child));
316 module = module->m_children.back().get();
320 module = iter->get();
323 module->m_level = level;
◆ qof_log_shutdown()
void qof_log_shutdown |
( |
void |
| ) |
|
Be nice, close the logfile if possible.
Definition at line 268 of file qoflog.cpp.
270 if (fout && fout != stderr && fout != stdout)
278 g_free(function_buffer);
279 function_buffer = NULL;
282 if (_modules != NULL)
287 if (previous_handler != NULL)
289 g_log_set_default_handler(previous_handler, NULL);
290 previous_handler = NULL;