Elasticsearch:Node.js ECS 日志记录 - Winston

这是继上一篇文章 "Elasticsearch:Node.js ECS 日志记录 - Pino" 的续篇。我们继续上一篇文章来讲述使用 Winston 包来针对 Node.js 应用生成 ECS 向匹配的日子。此 Node.js 软件包为 winston 记录器提供了格式化程序,与 Elastic Common Schema (ECS) 日志记录兼容。结合 Filebeat 发送器,你可以在 Elastic Stack 中的一处监控所有日志。支持 winston 3.x 版本 >=3.3.3。

设置

安装

npm install @elastic/ecs-winston-format
npm install winston

配置

winston-logging.js

const winston = require('winston');
const { ecsFormat } = require('@elastic/ecs-winston-format');

const logger = winston.createLogger({
  format: ecsFormat(/* options */),  // 1
  transports: [
    new winston.transports.Console()
  ]
});

logger.info('hi');
logger.error('oops there is a problem', { err: new Error('boom') });
  • 将 ECS 格式化程序传递给 winston。

上面的代码的运行结果为:

配置 Filebeat

Filebeat 7.16+

filebeat.yml

filebeat.inputs:
- type: filestream     # 1
  paths: /path/to/logs.json
  parsers:
    - ndjson:
      overwrite_keys: true # 2
      add_error_key: true  # 3
      expand_keys: true    # 4

processors: // 5
  - add_host_metadata: ~
  - add_cloud_metadata: ~
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~
  1. 使用 filestream 输入从活动日志文件中读取行。
  2. 如果发生冲突,解码的 JSON 对象的值将覆盖 Filebeat 通常添加的字段(type、source、offset 等)。
  3. 如果发生 JSON 解组错误,Filebeat 将添加 "error.message" 和 "error.type: json" 键。
  4. Filebeat 将递归地从解码的 JSON 中去掉点键,并将其扩展为分层对象结构。
  5. 处理器可增强你的数据。请参阅 processors 以了解更多信息。

Filebeat < 7.16

filebeat.yml

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: ~

有关更多信息,请参阅 Filebeat 参考

如何使用

winston-logging.js

const winston = require('winston');
const { ecsFormat } = require('@elastic/ecs-winston-format');

const logger = winston.createLogger({
  level: 'info',
  format: ecsFormat(/* options */), // 1
  transports: [
    new winston.transports.Console()
  ]
});

logger.info('hi');
logger.error('oops there is a problem', { foo: 'bar' });
  1. 请参阅下面的可用选项。

    node winston-logging.js | jq .

运行此脚本(可在此处获得)将产生类似上面内容的日志输出。

格式化程序负责将数据序列化为 JSON,因此你无需添加 json 格式化程序。此外,格式化程序会自动生成 timestamp,因此你无需添加 timestamp 格式化程序。

Error logging

默认情况下,格式化程序会将 Error 实例的 err 元字段转换为 ECS Error 字段。例如例子

winston-logging.js

const winston = require('winston');
const { ecsFormat } = require('@elastic/ecs-winston-format');
const logger = winston.createLogger({
  format: ecsFormat(), 
  transports: [
    new winston.transports.Console()
  ]
});

const myErr = new Error('boom');
logger.info('oops', { err: myErr }); 

可以通过 convertErr: false 选项禁用对 err 元字段的特殊处理:

winston-logging.js

const winston = require('winston');
const { ecsFormat } = require('@elastic/ecs-winston-format');
const logger = winston.createLogger({
  format: ecsFormat({convertErr: false} ), 
  transports: [
    new winston.transports.Console()
  ]
});

const myErr = new Error('boom');
logger.info('oops', { err: myErr }); 

HTTP 请求和响应日志记录

使用 convertReqRes: true 选项,格式化程序将在分别作为 req 和 res 元字段传递时自动转换 Node.js 核 requestresponse 对象。

winston-logging.js

const http = require('http');
const winston = require('winston');
const { ecsFormat } = require('@elastic/ecs-winston-format');

const logger = winston.createLogger({
  level: 'info',
  format: ecsFormat({ convertReqRes: true }), // 1
  transports: [
    new winston.transports.Console()
  ]
});

const server = http.createServer(handler);
server.listen(3000, () => {
  logger.info('listening at http://localhost:3000')
});

function handler (req, res) {
  res.setHeader('Foo', 'Bar');
  res.end('ok');
  logger.info('handled request', { req, res }); // 2
}
  1. 使用 convertReqRes 选项
  2. 记录 req 和/或 res 元字段

这将使用 ECS HTTP 字段生成包含请求和响应信息的日志。例如例子

在上面,我们需要访问 http://localhost:3000 才能看到如上所示的日子信息。

使用 APM 进行日志关联

此 ECS 日志格式化程序与 Elastic APM 集成。如果你的 Node 应用正在使用 Node.js Elastic APM Agent,则会将多个字段添加到日志记录中,以关联 APM 服务或跟踪和日志数据:

例如,运行 examples/http-with-elastic-apm.jscurl -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": "7fd75f0f33ff49aba85d060b46dcad7e",
  "transaction.id": "6c97c7c1b468fa05"
}

这些 ID 与 APM 代理报告的跟踪数据相匹配。

可以通过 apmIntegration: false 选项明确禁用与 Elastic APM 的集成,例如:

const logger = winston.createLogger({
  format: ecsFormat({ apmIntegration: false }),
  // ...
})

限制和注意事项

ecs-logging 规范建议日志记录中的前三个字段应为 @timestamp、log.level 和 message。从 1.5.0 版开始,此格式化程序不遵循此建议。这是可能的,但需要在 ecsFields 中为每个日志记录创建一个新对象。鉴于 ecs-logging 字段的排序是为了便于阅读,并且不会影响互操作性,因此决定优先考虑性能。

参考

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} 的默认值。

为 winston 创建以 ECS 日志记录格式发出的格式化程序。这是一种处理 ecsFields([options])ecsStringify([options]) 的单一格式。以下两个是等效的:

const { ecsFormat, ecsFields, ecsStringify } = require('@elastic/ecs-winston-format');
const winston = require('winston');

const logger = winston.createLogger({
  format: ecsFormat(/* options */),
  // ...
});

const logger = winston.createLogger({
  format: winston.format.combine(
    ecsFields(/* options */),
    ecsStringify()
  ),
  // ...
});

ecsFields([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} 的默认设置。

为 winston 创建一个格式化程序,将日志记录信息对象上的字段转换为 ECS 日志记录格式。

ecsStringify([options])

为 winston 创建一个格式化程序,将日志记录字符串化/序列化为 JSON。

这类似于 logform.json()。它们都使用 safe-stable-stringify 包来生成 JSON。一些区别:

  • 此字符串化器跳过序列化 level 字段,因为它不是 ECS 字段。
  • Winston 提供了一个将 bigint 转换为字符串的 replacer。这样做的理由是 JavaScript JSON 解析器在解析 bigint 时会丢失精度。反对的理由是 BigInt 将类型更改为字符串而不是数字。目前,此字符串化器不会将 BitInt 转换为字符串。
相关推荐
hai4117419624 分钟前
mysql 与postgresql 的区别(gpt4)
数据库·mysql·postgresql
知识分享小能手14 分钟前
mysql学习教程,从入门到精通,SQL 删除数据(DELETE 语句)(19)
大数据·开发语言·数据库·sql·学习·mysql·数据开发
白总Server28 分钟前
MongoDB解说
开发语言·数据库·后端·mongodb·golang·rust·php
冰镇毛衣34 分钟前
2.4 数据库表字段约束
数据库·sql·mysql
&木头人&41 分钟前
oracle select字段有子查询会每次执行子查询吗
数据库·oracle
冰镇毛衣41 分钟前
数据库简介
开发语言·数据库·sql·oracle
(⊙o⊙)~哦42 分钟前
oracle查询历史操作记录
数据库·oracle
无休居士1 小时前
【实践】应用访问Redis突然超时怎么处理?
数据库·redis·缓存
M-bao1 小时前
缓存数据和数据库数据一致性问题
数据库·缓存
不二师妹1 小时前
硬盘数据恢复必备:4 款强大硬盘数据恢复软件推荐!
数据库·数据恢复·数据恢复软件·硬盘数据恢复·文件找回·恢复大师