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;