【发布时间】:2023-03-23 17:10:01
【问题描述】:
从 docker 容器中将结构化日志写入日志的最佳方式是什么?
例如,我有一个使用sd_journal_send 编写的应用程序 我没有更改应用程序,而是尝试通过
-v /var/log/systemd/journal:/var/log/systemd/journal
它适用于我的 Ubuntu 16.04 桌面,但不适用于运行应用程序的 CoreOS 实例(使用 Ubuntu 16.04 基础映像)。我不太明白为什么。也许有更好的方式发送到期刊?
docker journald 输出日志记录选项有哪些限制?它似乎不支持应用程序编写的不仅仅是消息字段。
--
所以我发现我需要-v /dev/log:/dev/log
但是还有一个问题就是没有关联到启动docker容器的服务文件。手动添加 UNIT: servicename.service 没有解决它。因此,在查看和发送服务日志时,它与 exe 相关联,但与容器或服务无关。谁遇到了这些问题,您是如何解决的?
-- 好的,让我稍微扩展一下。
C 程序可以这样写入 systemd 日志:
#include <systemd/sd-journal.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
sd_journal_send("MESSAGE=Hello World!",
"MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555",
"PRIORITY=5",
"HOME=%s", getenv("HOME"),
"TERM=%s", getenv("TERM"),
"PAGE_SIZE=%li", sysconf(_SC_PAGESIZE),
"N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN),
NULL);
return 0;
}
这会写入日志并添加自定义字段,如 HOME、TERM、PAGE_SIZE 等。当我使用 journalbeat 将它们发送到 ELK 堆栈时,这些字段在 elasticsearch 中很好地结束,我可以直接搜索它们。
但是,docker 似乎只是简单地获取应用程序的标准输出,并将其提供给日志,只添加了几个字段。例如CONTAINER_ID。
在 docker 容器中使用这样的程序,然后从服务文件运行它们会产生一个小问题。
1) 我必须通过一些目录和设备文件才能使用 sd_journal_send 写入。
2) 如果您从 systemd .service 文件启动容器并希望使用 journalctl -u servicename 并查看消息,则看不到这些日志消息,因为它们以不同的路径进入日志并且没有得到与运行它们的服务相关联。
3) 您可以使用 docker 的 journald 日志记录驱动程序添加一些任意字段/标签,它们是固定的,一次添加会出现在每条发送的消息上并且不会改变。它们不是我想从上面的 C 代码中获得的动态字段。
从本质上讲,journald 日志驱动程序在我的情况下是不够的。
关于如何链接服务名称以便 journalctl -u 显示来自 sd_journal_send 的日志消息的任何建议?那样就可以解决问题了。
-- 我找到了解决方案。我会把答案放在下面,以防其他人对我的解决方法感兴趣。
【问题讨论】:
-
Docker journald logging driver 会做你想做的事吗?除了日志消息,它还存储其他元数据,如
CONTAINER_ID、CONTAINER_NAME、CONTAINER_TAG等。 -
我可能没有说清楚。我需要添加自己的字段并将其全部绑定在同一个单元中。发生的事情基本上是
journalctl -u在从 systemd 服务文件启动 docker 容器应用程序时将其视为另一个单元。 Docker 是问题所在。我将不得不深入研究源代码并查看它支持的 docker 中的 sysyemd 日志记录驱动程序。可能需要扩展它。 -
@TarunLalwani - 不。
-
如何在 Ubuntu 16.04 上编译它?我得到
vagrant@vagrant:~/journald$ gcc test.c /tmp/ccLHPQPH.o: In functionmain': test.c:(.text+0x8b): undefined reference tosd_journal_send_with_location' collect2: error: ld returned 1 exit status