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

Posted

技术标签:

【中文标题】是否可以在 GLib 新结构化日志记录中为每个域/日志级别设置不同的写入器函数?【英文标题】:Is it possible to set different writer functions per domain/log_level in GLib new structured logging? 【发布时间】:2021-07-17 22:25:10 【问题描述】:

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, my_log_handler, NULL);

但是,正如文档所说:

如果启用结构化日志记录,这将无效;请参阅使用 结构化日志记录。

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

【问题讨论】:

【参考方案1】:

这不可能吗?

如果你真的想要,它仍然是,但根据用例,最好不要(见答案的第二部分)。

使用结构化日志实现自定义处理日志的新方法是 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, fields, n_fields, 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 方式启动,因此要查看日志,您已经必须查看系统日志,例如使用 journalctl

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

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

# Only show logs of the application with the given commandline name
$ journalctl _COMM=my-application-name
# Only show logs of your application with a given pid
$ journalctl _PID=$YOUR_APPS_PID
# Only show logs of your application with level WARNING or higher
$ journalctl -p warning
# Only show logs with with the given GLib domain
$ journalctl -f GLIB_DOMAIN=Gtk

【讨论】:

以上是关于是否可以在 GLib 新结构化日志记录中为每个域/日志级别设置不同的写入器函数?的主要内容,如果未能解决你的问题,请参考以下文章

循环遍历列表映射以在一个资源块中为多个域创建 DNS 记录

linux 进程间通信 dbus-glib实例详解三(下) 数据类型和dteeth(类型签名type域)(层级结构:服务Service --> Node(对象object) 等 )(附代码)

Glib 对 C 函数进行单元测试

在 Laravel 4.2 中为每个公司创建目录(命名为 Today Date)并编写日志文件(命名为 CompanyName)

在db中为每个“对话”使用新的SQL表

如何在 mfc 中为多线程应用程序创建通用日志文件?