是否可以在 GLib 新结构化日志记录中为每个域/log_level 设置不同的编写器函数?

问题描述

GLib 有一个有趣的功能:能够为不同的域和日志级别设置不同的日志记录(即:显示或保存等)功能,例如:

/* Set handler for warnings from empty (application) domain */
g_log_set_handler (NULL,G_LOG_LEVEL_WARNING,my_log_handler,NULL);

/* Set handler for critical messages from Gtk+ */
g_log_set_handler ("Gtk",G_LOG_LEVEL_CRITICAL,NULL);

但是,正如文档所说:

如果启用了结构化日志,这将不起作用;见使用 结构化日志。

我没有找到与此功能相关的任何其他内容(即:每个域/级别处理程序)。这不可能吗?为什么 GLib 会放弃这么有用的功能

解决方法

这不可能吗?

如果您真的想要,它仍然是,但根据用例,不这样做可能更明智(请参阅答案的第二部分)。

使用结构化日志实现自定义处理日志的新方法是通过 g_log_set_writer_func()

例如:

#define G_LOG_USE_STRUCTURED
#include <glib.h>

static GLogWriterOutput
my_log_writer_func (GLogLevelFlags log_level,const GLogField *fields,size_t n_fields,void *user_data)
{
  if (log_level & G_LOG_LEVEL_CRITICAL) {
    // Do something special with criticals

    // For example purposes,let's just log it to stdout/stderr
    return g_log_writer_standard_streams (log_level,fields,n_fields,user_data);
  }

  if (log_level & G_LOG_LEVEL_DEBUG) {
    // This is not something you should do since it will make
    // debugging harder,but let's just do it for example purposes:
    // by returning G_LOG_WRITER_HANDLED without actually logging it,// the log message will not be outputted anywhere
    return G_LOG_WRITER_HANDLED;
  }

  // If you _really_ want to,you can still check on the GLib domain,// as it will be set in one of the GLogFields

  // Default case: use the default logger
  return g_log_writer_default (log_level,user_data);
}

int
main (int argc,char *argv[])
{
  g_log_set_writer_func (my_log_writer_func,NULL,NULL);

  // Run your application
}

为什么 GLib 会放弃这么有用的功能?

正如我之前提到的,GLib 并不是很难放弃对自定义日志实现的支持(请注意,这一切仅在您显式启用结构化日志时才有效)。我相信总体思路是越来越多的 GUI 应用程序正在从桌面(例如 GNOME Shell)或其他 UI 方式启动,因此要查看日志,您必须查看系统日志,例如使用 {{1} }.

此时,当您可以使用系统日志时,在日志级别、日志域等上过滤日志消息会容易得多。它还可以防止必须告诉用户“再次运行它,但现在使用这些随机环境变量,如 journalctl”,因为他们可能不知道如何运行命令。这也可能是很难重现的东西,因此手头准备好调试日志会很有用。

使用 journalctl 的一些示例命令是:(请注意,您可以轻松组合过滤器)

G_MESSAGES_DEBUG=all