结构化日志记录从docker容器中记录日志

时间:2017-08-14 20:58:53

标签: docker systemd coreos

从docker容器中编写结构化日志到journald的最佳方法是什么?

例如,我有一个使用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堆栈时,这些字段在弹性搜索中很好地结束,我可以直接搜索它们。

但是,看起来docker只需要使用stdout的应用程序,并将其添加到日志中,只添加了几个字段。例如CONTAINER_ID。

在docker容器中使用这样的程序,然后从服务文件运行它时会产生一些问题。

1)我必须通过一些目录和设备文件来使用sd_journal_send写入。

2)如果你从systemd .service文件启动容器并希望使用journalctl -u servicename并查看消息,那些日志消息就不会被看到,因为它们进入了不同路径的日志并且没有&# 39;与运行它们的服务相关联。

3)你可以使用docker的日志记录驱动程序添加一些任意字段/标签,它们是固定的,一次性添加将出现在每个发送的消息上并且不变。它们不是我想要的动态字段,而是来自上面的C代码。

基本上,记录日志驱动程序在我的情况下是不够的。

有关如何链接服务名称的任何建议,以便journalctl -u显示来自sd_journal_send的日志消息?因为那会解决它。

- 我找到了解决方案。我会在下面给出答案,以防其他人对我如何解决它感兴趣。

2 个答案:

答案 0 :(得分:1)

最终的解决方案变得非常简单。

我转而把我的短信写成纯粹的json。因此,journalctl -u现在可以工作并显示现在包含json数据的MESSAGE字段。

然后我使用journalbeat将其发送到logstash。

要logstash.conf,我添加了:

filter {
  json {
    source => "message"
  }
}

这样做是将json数据从消息字段扩展到顶层的单独字段,然后再将它们发送到elasticsearch。

可以找到有关logstash的json过滤器的详细信息here

答案 1 :(得分:1)

您需要挂载journald侦听的套接字。如果是ubuntu,则为/run/systemd/journal/socket。将此内部人员映射到docker容器,它可以正常工作

在你的示例代码中使用strace计算出来

sendmsg(3, {msg_name(29)={sa_family=AF_LOCAL, sun_path="/run/systemd/journal/socket"}, 
msg_iov(23)=[{"CODE_FILE=test.c", 16}, {"\n", 1}, {"CODE_LINE=13", 12}, {"\n", 1}, {"CODE_FUNC=main", 14}, {"\n", 1}, 
{"MESSAGE=Hello World!", 20}, {"\n", 1}, {"MESSAGE_ID=52fb62f99e2c49d89cfbf"..., 43}, {"\n", 1}, {"PRIORITY=5", 10}, {"\n", 1}, 
{"HOME=/home/vagrant", 18}, {"\n", 1}, {"TERM=xterm-256color", 19}, {"\n", 1}, {"PAGE_SIZE=4096", 14}, {"\n", 1}, 
{"N_CPUS=1", 8}, {"\n", 1}, {"SYSLOG_IDENTIFIER=", 18}, {"a.out", 5}, {"\n", 1}], msg_controllen=0, msg_flags=0}, MSG_NOSIGNAL) = 208

使用下面的

在ubuntu docker容器中测试它
docker run -v /run/systemd/journal/socket:/run/systemd/journal/socket -v $PWD:/jd -it -w /jd ubuntu:16.04 ./a.out

我在journalctl -f(主持人)

上有一个条目
Aug 15 21:40:33 vagrant a.out[11263]: Hello World!