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 330 of file qoflog.cpp.
333 if (level > current_max)
335 if (level <= default_level)
337 auto module = get_modules();
339 if (level <= module->m_level)
345 auto domain_vec = split_domain(domain);
347 for (
const auto& part : domain_vec)
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; });
354 if (iter == module->m_children.end())
357 if (level <= (*iter)->m_level)
360 module = iter->get();
◆ qof_log_indent()
| void qof_log_indent |
( |
void |
| ) |
|
Indents one level; see ENTER macro.
Definition at line 130 of file qoflog.cpp.
132 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 156 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 207 of file qoflog.cpp.
209 gboolean warn_about_missing_permission = FALSE;
210 auto modules = get_modules();
212 if (!qof_logger_format)
213 qof_logger_format = g_strdup (
"* %s %*s <%s> %*s%s%s");
220 if (fout !=
nullptr && fout != stderr && fout != stdout)
223 fname = g_strconcat(log_filename,
".XXXXXX.log",
nullptr);
225 if ((fd = g_mkstemp(fname)) != -1)
227 #if PLATFORM(WINDOWS) 230 fout = g_fopen(fname,
"wb");
233 g_assert(g_strcmp0(log_filename,
"/dev/null") != 0);
237 g_rename(fname, log_filename);
238 fout = fdopen(fd,
"w");
241 warn_about_missing_permission = TRUE;
245 warn_about_missing_permission = TRUE;
254 if (previous_handler ==
nullptr)
255 previous_handler = g_log_set_default_handler(log4glib_handler, modules);
257 if (warn_about_missing_permission)
259 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 421 of file qoflog.cpp.
423 const gchar *levels_group =
"levels", *output_group =
"output";
424 GError *err =
nullptr;
425 GKeyFile *conf = g_key_file_new();
427 if (!g_key_file_load_from_file(conf, filename, G_KEY_FILE_NONE, &err))
429 g_warning(
"unable to parse [%s]: %s", filename, err->message);
434 DEBUG(
"parsing log config from [%s]", filename);
435 if (g_key_file_has_group(conf, levels_group))
438 unsigned int key_idx;
440 gint logger_max_name_length = 12;
441 gchar *str =
nullptr;
443 levels = g_key_file_get_keys(conf, levels_group, &num_levels,
nullptr);
445 for (key_idx = 0; key_idx < num_levels && levels[key_idx] !=
nullptr; key_idx++)
448 gchar *logger_name =
nullptr, *level_str =
nullptr;
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);
455 DEBUG(
"setting log [%s] to level [%s=%d]", logger_name, level_str, level);
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);
471 if (g_key_file_has_group(conf, output_group))
474 unsigned int output_idx;
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++)
480 gchar *key = outputs[output_idx];
483 if (g_ascii_strcasecmp(
"to", key) != 0)
485 g_warning(
"unknown key [%s] in [outputs], skipping", key);
489 value = g_key_file_get_string(conf, output_group, key,
nullptr);
490 DEBUG(
"setting [output].to=[%s]", value);
497 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 145 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 297 of file qoflog.cpp.
299 if (!log_module || level == QOF_LOG_FATAL)
302 if (level > current_max)
305 auto module_parts = split_domain(log_module);
306 auto module = get_modules();
307 for (
auto part : module_parts)
309 auto iter = std::find_if(module->m_children.begin(),
310 module->m_children.end(),
312 return child && part == child->m_name;
314 if (iter == module->m_children.end())
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();
322 module = iter->get();
325 module->m_level = level;
◆ qof_log_shutdown()
| void qof_log_shutdown |
( |
void |
| ) |
|
Be nice, close the logfile if possible.
Definition at line 264 of file qoflog.cpp.
266 if (fout && fout != stderr && fout != stdout)
272 if (qof_logger_format)
274 g_free (qof_logger_format);
275 qof_logger_format =
nullptr;
280 g_free(function_buffer);
281 function_buffer =
nullptr;
284 if (_modules !=
nullptr)
289 if (previous_handler !=
nullptr)
291 g_log_set_default_handler(previous_handler,
nullptr);
292 previous_handler =
nullptr;