使用 Pino 进行 ECS 日志记录
编辑使用 Pino 进行 ECS 日志记录
编辑此 Node.js 包为 pino 日志记录器提供了一个格式化程序,该程序与 Elastic Common Schema (ECS) 日志记录兼容。 与 Filebeat 传输器结合使用,您可以在 Elastic Stack 中的一个位置 监控您的所有日志。pino
支持 6.x、7.x 和 8.x 版本。
设置
编辑步骤 1:安装
编辑$ npm install @elastic/ecs-pino-format
步骤 2:配置
编辑const { ecsFormat } = require('@elastic/ecs-pino-format'); const pino = require('pino'); const log = pino(ecsFormat(/* options */)); log.info('hi'); log.error({ err: new Error('boom') }, 'oops there is a problem'); // ...
这将配置 Pino 的 |
请参阅下面的用法讨论和示例。
步骤 3:配置 Filebeat
编辑一旦日志格式化为 ECS 格式,收集日志的最佳方法是使用 Filebeat
- 请按照 Filebeat 快速入门
- 将以下配置添加到您的
filebeat.yaml
文件中。
对于 Filebeat 7.16+
filebeat.yaml。
filebeat.inputs: - type: filestream paths: /path/to/logs.json parsers: - ndjson: overwrite_keys: true add_error_key: true expand_keys: true processors: - add_host_metadata: ~ - add_cloud_metadata: ~ - add_docker_metadata: ~ - add_kubernetes_metadata: ~
使用 filestream 输入从活动日志文件中读取行。 |
|
如果发生冲突,解码的 JSON 对象中的值将覆盖 Filebeat 通常添加的字段(type、source、offset 等)。 |
|
如果出现 JSON 反序列化错误,Filebeat 将添加 "error.message" 和 "error.type: json" 键。 |
|
Filebeat 将递归地对解码的 JSON 中的键进行去点化,并将其展开为分层对象结构。 |
|
处理器可以增强您的数据。 请参阅 处理器 了解更多信息。 |
对于 Filebeat < 7.16
filebeat.yaml。
filebeat.inputs: - type: log paths: /path/to/logs.json json.keys_under_root: true json.overwrite_keys: true json.add_error_key: true json.expand_keys: true processors: - add_host_metadata: ~ - add_cloud_metadata: ~ - add_docker_metadata: ~ - add_kubernetes_metadata: ~
- 确保您的应用程序将日志记录到 stdout/stderr。
- 请按照 在 Kubernetes 上运行 Filebeat 指南进行操作。
- 启用 基于提示的自动发现(取消注释
filebeat-kubernetes.yaml
中的相应部分)。 - 将这些注释添加到使用 ECS 日志记录器的 pod 中。 这将确保正确解析日志。
- 确保您的应用程序将日志记录到 stdout/stderr。
- 请按照 在 Docker 上运行 Filebeat 指南进行操作。
- 启用 基于提示的自动发现。
- 将这些标签添加到使用 ECS 日志记录器的容器中。 这将确保正确解析日志。
docker-compose.yml。
有关更多信息,请参阅 Filebeat 参考。
用法
编辑const { ecsFormat } = require('@elastic/ecs-pino-format'); const pino = require('pino'); const log = pino(ecsFormat(/* options */)); log.info('Hello world'); const child = log.child({ module: 'foo' }); child.warn('From child');
请参阅下方提供的选项。 |
运行此代码将生成类似于以下内容的日志输出
{"log.level":"info","@timestamp":"2023-10-14T02:07:47.901Z","process.pid":56645,"host.hostname":"pink.local","ecs.version":"8.10.0","message":"Hello world"} {"log.level":"warn","@timestamp":"2023-10-14T02:07:47.901Z","process.pid":56645,"host.hostname":"pink.local","ecs.version":"8.10.0","module":"foo","message":"From child"}
错误日志记录
编辑默认情况下,格式化程序会将作为 Error 实例的 err
字段转换为 ECS Error 字段。 例如
const { ecsFormat } = require('@elastic/ecs-pino-format'); const pino = require('pino'); const log = pino(ecsFormat()); const myErr = new Error('boom'); log.info({ err: myErr }, 'oops');
将产生(为便于阅读而进行了美化)
% node examples/error.js | jq . { "log.level": "info", "@timestamp": "2021-01-26T17:02:23.697Z", ... "error": { "type": "Error", "message": "boom", "stack_trace": "Error: boom\n at Object.<anonymous> (..." }, "message": "oops" }
这与 Pino 的默认 err 序列化器类似并覆盖了它。 可以通过 convertErr: false
选项禁用对 err
字段的特殊处理
const log = pino(ecsFormat({ convertErr: false }));
HTTP 请求和响应日志记录
编辑使用 convertReqRes: true
选项,当分别作为 req
和 res
字段传递时,格式化程序将自动转换 Node.js 核心 request 和 response 对象。(此选项替换了 req
和 res
Pino 序列化器的使用。)
const http = require('http'); const { ecsFormat } = require('@elastic/ecs-pino-format'); const pino = require('pino'); const log = pino(ecsFormat({ convertReqRes: true })); const server = http.createServer(function handler (req, res) { res.setHeader('Foo', 'Bar'); res.end('ok'); log.info({ req, res }, 'handled request'); }); server.listen(3000, () => { log.info('listening at https://127.0.0.1:3000'); }
这将使用 ECS HTTP 字段生成包含请求和响应信息的日志。 例如
% node examples/http.js | jq . # using jq for pretty printing ... # run 'curl https://127.0.0.1:3000/' { "log.level": "info", "@timestamp": "2023-10-14T02:10:14.477Z", "process.pid": 56697, "host.hostname": "pink.local", "ecs.version": "8.10.0", "http": { "version": "1.1", "request": { "method": "GET", "headers": { "host": "localhost:3000", "user-agent": "curl/8.1.2", "accept": "*/*" } }, "response": { "status_code": 200, "headers": { "foo": "Bar" } } }, "url": { "full": "https://127.0.0.1:3000/", "path": "/" }, "client": { "address": "::ffff:127.0.0.1", "ip": "::ffff:127.0.0.1", "port": 49504 }, "user_agent": { "original": "curl/8.1.2" }, "message": "handled request" }
examples/ 目录显示了使用请求和响应日志记录的示例程序:使用 Express、使用 pino-http 中间件包等。
与 APM 的日志关联
编辑此 ECS 日志格式化程序与 Elastic APM 集成。如果您的 Node 应用程序正在使用 Node.js Elastic APM 代理,则会将许多字段添加到日志记录中,以关联 APM 服务或跟踪与日志记录数据
例如,运行 examples/http-with-elastic-apm.js 和 curl -i localhost:3000/
会生成具有以下内容的日志记录
% node examples/http-with-elastic-apm.js | jq . ... "service.name": "http-with-elastic-apm", "service.version": "1.4.0", "service.environment": "development", "event.dataset": "http-with-elastic-apm", "trace.id": "9f338eae7211b7993b98929046aed21d", "transaction.id": "2afbef5642cc7a3f", ...
这些 ID 与 APM 代理报告的跟踪数据匹配。
可以通过 apmIntegration: false
选项显式禁用与 Elastic APM 的集成,例如
const log = pino(ecsFormat({ apmIntegration: false }));
限制和注意事项
编辑ecs-logging 规范建议日志记录中的前三个字段必须是 @timestamp
、log.level
和 message
。 Pino 没有提供将 message
字段放在前面的机制。 鉴于 ecs-logging 字段的排序是为了人类可读性,并且不影响互操作性,因此这不被认为是重大问题。
Pino 当前提供的钩子不允许此包转换传递给 <logger>.child({ ... })
的字段。 这意味着,即使使用 convertReqRes
选项,调用 <logger>.child({ req })
也将不会将 req
转换为 ECS HTTP 字段。 对于 pino-http 的用户来说,这是一个轻微的限制,因为它会这样做。
参考
编辑ecsFormat([options])
编辑-
options
{type-object}
支持以下选项-
convertErr
{type-boolean}
是否将记录的err
字段转换为 ECS 错误字段。默认值:true
。 -
convertReqRes
{type-boolean}
是否将记录的req
和res
HTTP 请求和响应字段转换为 ECS HTTP、用户代理和 URL 字段。默认值:false
。 -
apmIntegration
{type-boolean}
是否启用 APM 代理集成。默认值:true
。 -
serviceName
{type-string}
“service.name” 值。如果指定,则此值将覆盖来自活动 APM 代理的任何值。 -
serviceVersion
{type-string}
“service.version” 值。如果指定,则此值将覆盖来自活动 APM 代理的任何值。 -
serviceEnvironment
{type-string}
“service.environment” 值。如果指定,则此值将覆盖来自活动 APM 代理的任何值。 -
serviceNodeName
{type-string}
“service.node.name” 值。如果指定,则此值将覆盖来自活动 APM 代理的任何值。 -
eventDataset
{type-string}
“event.dataset” 值。如果指定,则此值将覆盖使用${serviceVersion}
的默认值。
-
为配置 ECS 日志格式输出的 pino(...)
创建选项。