条带有 Fluentd 和 Graylog 的 Bunyan JSON 日志
如果您有一堆微服务启动并运行,那么将所有应用程序日志聚合到一个日志管理解决方案中是必须的。根据您部署应用程序的方式、部署应用程序的位置,有很多工具和解决方案可以实现这一目标。但是,选择正确的工具组合至关重要,因为您将在应用程序基础架构上进行足够的维护工作,而不是在出现故障时不时地重新实现日志聚合方案。在本文中,我将解释如何为基于 Node.js 的微服务设置如此出色的工具组合。
这是专注于使用 NodeJS 构建微服务架构的系列文章的第一篇。您可以访问以下系列的其余文章:
-
使用 Fluentd 和 Graylog 的 Bunyan JSON 日志(本文)
-
Node.js 应用程序中的错误管理
-
使用 MongoDB 实现事件溯源和 CQRS 模式
-
Canary 健康检查端点(即将推出)
-
使用 Node.js 编写 MongoDB 数据库迁移(即将推出)
在本文中,我们将讨论如何为运行在 Docker 上的一组 Node.js 微服务实现日志聚合机制。为简化起见,我将把所有东西都作为 Docker 容器运行以进行解释,但可以肯定的是,即使你在裸机上运行所有东西,你也可以实现相同的方案。
我们将使用
-
Bunyan 作为我们的 Node.js 应用程序的标准日志库
-
GrayLog 作为日志管理和可视化服务器,可以查看和分析我们所有的日志
-
Fluentd 作为中间日志收集器,它将从我们的应用程序中收集所有日志并推送到 GrayLog
我们的方法
[
](https://res.cloudinary.com/practicaldev/image/fetch/s--6UPAeM08--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1。 medium.com/max/667/1%2AxxZF327iwwU3qXAqYGCqxg.png)
我们将把每个 NodeJS 微服务作为一个单独的 docker 容器运行。我们将在同一个 docker 主机上将 Fluentd 作为单独的容器运行。
现在我们需要一种与 Fluentd 共享应用程序日志的方法,以便它可以将其发送到 GrayLog。这可以通过多种方式完成:
-
使用Fluentd docker log driver — 这种方式有很多限制,在玩的时候也会出现一些严重的问题。您可以在此处阅读有关的更多信息。
-
在每个应用程序容器本身内运行 Fluentd — 这是一种可行的方法。对此的一个担忧是,您的应用程序 docker 容器将与一个额外的依赖项捆绑在一起。如果您需要将 Fluentd 升级到最新版本,则必须更新应用程序 docker 映像本身并重新部署所有应用程序。
-
将 Fluentd 作为单独的容器运行,允许通过共享的挂载卷访问日志 — 在这种方法中,您可以将 docker 主机服务器上的目录作为卷挂载到每个容器上并写入日志进入那个目录。然后,您可以将同一目录挂载到 Fluentd 上,并允许 Fluentd 从该目录读取日志文件。这种方法将日志聚合器与您的应用程序容器分开,但它可能使 Fluentd 成为单点故障。对于日志聚合,这通常不是一个关键问题,因为 Fluentd 有能力从最后一个位置继续收集日志,如果它发生故障并出现。
除了上述方法之外,还有其他方法可以做到这一点,您可以根据自己的需要选择这些方法中的任何一种。但出于本文的目的,让我们使用上图所示的第 3 种方法。
现在让我们看看日志记录。
Node.js 应用程序的日志库
谈到日志记录,Node.js 应用程序有很多优秀的日志记录库。一些最常用的是 Bunyan、Winston、Log4js、Pino 和 blah blah blah。很长一段时间以来,我一直坚持使用 Bunyan,只是因为它使用简单,工作完美,我懒得转移到其他东西上。
我在使用 Bunyan 的第一天看到的一个令人讨厌的功能是,它以 JSON 格式记录。 Bunyan JSON 日志一点也不好看。如果您需要以漂亮的格式显示它,则必须通过bunyan二进制文件对其进行管道传输。

示例 Bunyan JSON 日志。

美化的班扬原木。那不是很好吗?
但很快我就意识到它有一些好处,尤其是在日志聚合方面。假设:如果我们以这种美化的格式编写 Bunyan 日志,并决定将其推送到 Graylog 会怎样。
您仍然可以通过fluentd使用日志,使用如下命名的正则表达式标记每个日志行,然后将其发送到 Graylog。
\[(?\<timestamp\>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\] (?\<level\>[A-Z]+): (?\<name\>.+)\/(?\<processId\>\d+) on (?\<hostname\>.+): (?\<message\>.+)
进入全屏模式 退出全屏模式
但是这种方法有两个缺点。
如果您决定向 Bunyan 日志记录添加新字段怎么办?
如果您使用过 Bunyan,您就会知道这是可能的,只要新属性名称不与名称、级别、主机名等默认字段冲突。每次添加新字段时,您的日志行都会与以前不同,您的旧正则表达式将无法识别它。然后,您必须使用更新的正则表达式重新部署 Fluentd 以识别新字段。
如果您的应用程序的日志包含动态添加的字段怎么办?
如果您在上面的美化日志中看到,有一些日志行以可选 (workerIdu003d<someId>) 结尾。这是因为上面的日志来自一个集群化的 NodeJS 应用程序并且每当工作进程转储日志时,它都会在 JSON 日志行中添加一个额外的字段,键为workerId,使用 Bunyan 中的log.child()。
这是 Bunyan 中一个非常有用的功能,称为子日志,您应用程序中的不同模块可以在日志消息中添加一个附加属性,以识别特定日志是从同一模块生成的。
如果您的应用程序将此类动态字段添加到日志行,则编写一个能够解析日志行中的所有动态字段以生成统一标记化输出的命名正则表达式可能会很麻烦。
JSON日志的优势
但是,如果您以默认 JSON 格式编写日志,即使您向其中添加新字段,它仍然是一个很好的 JSON,最重要的是,FluentD 能够将日志解析为 JSON。这真的很酷,因为新添加的字段或动态添加的字段将立即在 GrayLog 中用于分析,而无需任何额外的配置。
为此,我们需要,
-
使用 Bunyan(或任何其他记录为 JSON 的记录器)以 JSON 格式编写我们的日志,
-
从fluent读取日志并将每一行解析为JSON,
-
将解析的 JSON 数据转换为 Graylog GELF 格式(Graylog 可以理解)并发布到 Graylog。
似乎很容易。
配置 Fluentd
现在,我们需要准备 Fluentd 将日志解析为 JSON 并将它们以 GELF 格式推送到 Graylog。为此,我们需要这样配置 Fluentd。
然而,我们需要的 Fluentd 的确切功能并不是开箱即用的。 Fluentd 需要一个特殊的插件来以 GELF 格式发布日志。为此,我们将使用以下 Fluentd 插件:
emsearcy/fluent-plugin-gelf
缓冲流式输出插件到 GELF (Graylog2)
流利的插件-gelf
在 GitHub 上查看
但是,由于一个小警告,我不会按原样使用这个插件。所以我分叉了它,对它的代码做了一些小的改动,并将它用于我的目的。我将解释为什么在那之前我必须这样做,我们将继续使用我的版本,如下所示:
deepal/fluent-plugin-gelf
缓冲流式输出插件到 GELF (Graylog2)
流利的插件-gelf
在 GitHub 上查看
现在,我们将使用基础 docker 镜像构建我们自己的自定义 Fluentd docker 镜像。我们将把上面的插件和我们的 Fluentd 配置捆绑到我们的自定义镜像中。让我们为我们的图像使用以下 docker 文件:
将dockerfile下载到本地计算机上的目录中。要从这个dockerfile构建映像,我们需要 Fluentd GELF 插件 (out_gelf.rb) 和 Fluentd 配置 (fluentd.conf)
然后去上面的插件库,找到 FluentdGELF 插件位于这里命名为 out_gelf.rb。下载下来,复制到dockerfile的同一个目录下。
接下来,我们需要以下 Fluentd 配置(fluentd.conf),我们在其中配置输入源(应用程序日志)。
将其下载到与dockerfile相同的目录并相应地更改您的 docker 主机和 GELF UDP 输入端口(如果您选择 TCP,您可能需要一些额外的配置)。在同一个配置中,您的附加日志源可以被<source>个块包围。
<store>块中的@type gelf指示 Fluentd 使用我们的 GELF 插件来将日志推送到 GrayLog。
现在让我们构建自定义 docker 容器。
docker built -t myfluentd .
进入全屏模式 退出全屏模式
然后,运行容器并将主机 /var/log/apps/ 目录挂载到 Fluentd 容器上。
docker run -v /var/log/apps:/var/log/apps -d myfluentd
进入全屏模式 退出全屏模式
Fluentd 容器现在应该可以访问您在 fluentd.conf 中配置的应用程序日志。如果 Fluentd 和 Graylog 之间的连接正常,Graylog 现在应该像魅力一样在仪表板中显示您的日志!
[
](https://res.cloudinary.com/practicaldev/image/fetch/s--bBVgEqS0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1。 medium.com/max/1024/1%2AytCugGgj2kA2TcxhyFj2rg.png)
最后一句话
如果你还记得,我说过我不能按原样使用 Fluentd GELF 插件。原因是,Bunyan 日志中的 level 字段与 Fluentd GELF 插件理解的标准 syslog 级别代码不兼容。所以,我必须在插件的 ruby 脚本中进行一些更改以使其正常工作。如上图所示。 Bunyan 级别现在在 GrayLog 中显示为字段级别_code。
您可以使用以下 docker-compose 文件在您的机器中快速设置 GrayLog、ElasticSearch、MongoDB 和 Fluentd 以便在本地进行测试(确保您设置的图像名称正确)。
如果您有任何问题或建议可以更好地做到这一点,请随时提出任何意见。谢谢你。
更多推荐
所有评论(0)