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

07-12 1651阅读

这是继上一篇文章 “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。

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

    Elasticsearch:Node.js 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

    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 .

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

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

    格式化程序负责将数据序列化为 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 }); 

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

    可以通过 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 }); 

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

    HTTP 请求和响应日志记录

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

    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 字段生成包含请求和响应信息的日志。例如例子:

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

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

    使用 APM 进行日志关联

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

    • 当前跟踪 span 时调用的日志语句(例如 logger.info(...))将包括跟踪字段 — trace.id、transaction.id、span.id。
    • 由 APM 代理确定或在 APM 代理上配置的多个服务标识符字段允许在 Kibana 中的服务和日志之间进行交叉链接 — service.name、service.version、service.environment、service.node.name。
    • event.dataset 在 Elastic Observability 应用中启用日志率异常检测。

      例如,运行 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": "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 转换为字符串。
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]