不久前,GLib 获得了一种新的“结构化日志记录”功能。与此同时,它也获得了将日志写入 systemd 日志的功能。显然,GLib 中的日志记录变得更加复杂,并且可能会让人感到困惑。
本文旨在澄清这些问题。
结构化与非结构化
传统的 GLib 日志记录工具是 g_message()
、g_debug()
等宏,它们最终会调用 g_log()
函数,然后该函数使用通过 g_log_set_handler()
设置的日志处理程序来执行实际写入操作。您可以将任何您想要的信息放入日志中,但必须将其全部格式化为单个字符串,即消息。
g_debug ("You have %d eggs", 12 + 2); g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "You have %d eggs", 12 + 2);
使用新的结构化日志记录工具,您可以调用 g_log_structured()
,然后它使用日志写入函数来执行写入操作。到目前为止,这与较旧的日志记录工具非常相似。结构化日志的优点是,您可以将多个字段放入日志中,而无需将其全部格式化为字符串。相反,您可以传递一个日志字段数组,这些字段是键值对。
g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "CODE_FILE", "mysource.c", "CODE_LINE", 312, "MESSSAGE_ID", "06d4df59e6c24647bfe69d2c27ef0b4e", "MESSAGE", "You have %d eggs", 12 + 2);
这里的 CODE_FILE
、CODE_LINE
和 MESSAGE_ID
只是“标准”字段的示例。您也可以发明自己的字段。请注意,您仍然可以使用 printf
风格的格式化来处理 MESSAGE
字段。
因此,GLib 现在有两个独立的日志记录工具。为了使事情更有趣,我们允许您将 g_message()
、g_debug()
等包装宏重定向为在底层使用 g_log_structured()
而不是 g_log()
。为此,请在包含 glib.h
之前定义 G_LOG_USE_STRUCTURED
宏。
为什么这很有用?一方面,它可以省去您替换所有 g_debug()
的麻烦,并且仍然可以利用结构化日志记录的一些优点 – 以这种方式使用时,传统的宏使用单独的字段来表示日志域、代码文件和行以及其他一些字段,这对于在生成的日志中进行过滤和搜索很有帮助,特别是在 systemd 日志中。
另一个优点是,您可以使用单个后端,即日志写入函数,来控制新旧日志调用最终的去向。
我的日志都去哪了?
结构化日志记录通常与 systemd 日志相关联。因此,人们期望 g_log_structured()
的输出进入日志也就不足为奇了。对于服务,或者当您从桌面图标启动应用程序时,这确实非常有用。但是,如果您从终端运行它,您可能希望在那里看到它的输出。
为了满足这些相互竞争的需求,GLib 默认的日志写入函数试图变得智能。如果它检测到 stderr
被重定向到 journald 套接字,那么它会将其结构化输出写入日志。否则,它会格式化一条消息并将其写入 stderr
。
GNOME Shell 和 DBus 都会在启动应用程序或服务时安排将 stderr
重定向到日志。将 stderr
显式重定向到日志的一种方法是在 systemd-cat
下运行您的应用程序。
systemd-cat my-app-that-logs
如果您确定要将日志始终发送到日志,您可以告诉 GLib 使用执行此操作的日志写入器
g_log_set_writer_func (g_log_writer_journald, NULL, NULL)
超越默认
即使 GLib 默认提供的日志写入函数应该满足许多需求,您可能仍然需要编写自己的函数。在这种情况下,GLib 有许多有用的函数可以帮助您,例如 g_log_writer_format_fields()
、g_log_writer_is_journald()
或 g_log_writer_supports_color()
。
祝您日志记录愉快!
GLib 日志记录文档说:“不要在库代码中使用 g_warning()。改用 GError。”
这很不现实。如果可以将错误映射到 API 函数调用,那么很好,GError 当然是首选方法。但是在任何足够复杂的库中,这种情况都很少发生……。
@Michael:其意图是“不要使用 g_warning()/g_critical() 来进行可恢复的错误报告,并指望用户来报告它们”。警告(和严重)旨在用于程序员错误和内部状态一致性检查 — 并且预期任何遵循警告的内容都是未定义的行为。就我个人而言,我更喜欢断言而不是仅仅发出警告,因为这样可以捕获真正的程序员错误,但是警告通常具有更容易理解的消息。
另一方面,GError 不用于程序员错误或内部状态检查:首先也是最重要的是:GError 仅应用于报告可恢复的运行时错误,绝不用于报告编程错误。
当然,文档可以改进。请随时提交错误报告。