为什么我的 AWS Cloudwatch 日志将 JSON 字符串分成两行?

问题描述 投票:0回答:1

我正在调试一个从 AWS Lambdas 打印单行 JSON 的应用程序。当我查看 CloudWatch 日志时,我发现“有时”它们被分成多行。

Screenshot of Cloudwatch Logs

在此图中,您可以看到 JSON 字符串被分成两行(用红色框表示)。我已经验证,当我连接两个部分时,它会生成一个有效的 JSON 字符串。第一个块的长度为 65536 个字符。第二块的长度为 24245 个字符。 2 行总共 89781 个字符。

对此有解释或记录的行为吗?或者,也许是我配置错误的 AWS 设置?我希望这些日志显示为一行。

我的日志代码

process.stdout.write(fastStringify(shrinkify(obj)) + "\n");

哪里

function shrinkify(obj: Object): string {
  // removes key-values until
  // Buffer.byteLength(JSON.stringify(obj), "utf8")
  // is < X
}

function fastStringify(obj: Object): string {
  try {
    return JSON.stringify(obj);
  } catch (e) {
    return require("safe-json-stringify")(obj);
  }
}

我正在使用以下 Lambda 运行时

Node.js 14
Architecture x86_64

以下是

dependencies
文件中一些可能相关的
package.json

{
  "dependencies": {
    "aws-sdk": "2.1308.0",
    "express": "4.18.2",
    "opentracing": "0.14.7",
    "safe-json-stringify": "1.2.0",
    "serverless-http": "2.7.0"
  }
}

观察

有趣的是,这种情况只是偶尔发生。我见过大于 65536 个字符且未拆分的日志。例如,1 行有 89775 个字符。

另一个有趣的事情是,分裂似乎总是发生在 2 的某个幂上(例如 2^16、2^17 等)。 2^18 除外。似乎是 2^18 - 26。Cloudwatch Log 事件有 256kb 限制,所以也许这 26 个字节是为元数据保留的?

我还发现了一个大得离谱的 JSON 日志。 Cloudwatch 分为 5 个部分。

1st: 131072 characters
2nd: 262118 characters
3rd: 262118 characters
4th: 262118 characters
5th:  56603 characters

最后,如果我们回顾上面的附图,我发现很有趣的是,JSON 字符串的第二部分出现在 Lambda 执行的 END

REPORT
之后。

假设1

CloudWatch 规定日志事件最大可达 256KB。目前尚不清楚如果它更大会发生什么,但网上的一些文章似乎说 Cloudwatch 会丢弃这些事件。

CloudWatch Logs 代理是导出日志的常用且推荐的方法。代理会跳过大小超过 256 KB 的日志事件。代理还会自动调整每个批次的长度以符合 1 MB 限制。

也许 Cloudwatch 实际上会在达到一定大小后分割日志事件?这无法解释为什么有些日志事件会被分割,而另一些则不会。它也没有解释为什么分割发生在长度小于 256kb 的情况下(例如 64kb,如上面的屏幕截图所示)。

参考文献

  • https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/cloudwatch_limits_cwl.html

  • https://www.techtarget.com/searchcloudcomputing/tip/Be-aware-of-these-CloudWatch-Logs-limits-and-quotas

假设2

也许我的节点模块之一正在覆盖

process.stdout.write

函数以在作为 Lambda 运行时考虑日志限制?我调查了

serverless-http
是否具有执行此操作的“功能”,但没有看到任何有关发生这种情况的报告。
没有进一步进展。

假设3

也许我的绳子里面有一个随机的

/r

/n
?我检查了附图中分割的边界。这些字符串都不存在。

假设4

也许 AWS Lambdas

stdout

异步流式传输到 Cloudwatch? ...当 lambda 在流仍在进行时退出时,它决定在这些边界处分割日志流,并在执行上下文结束后刷新剩余的流缓冲区?

这是我最有说服力的假设,但我找不到任何文章来支持这一点。这可以解释为什么 JSON 字符串的其他部分出现在 Lambda 日志的 

END

REPORT
之后。
参考文献

    node.js 的 console.log 是异步的吗?
解决方法

我决定实现 Shrinkify() 函数,如上面的代码片段所示。它会删除密钥,直到长度小于 X(可配置)。我将此限制设置为 64kb,以便日志显示为一行。

这很不幸,因为我将无法使用 CloudWatch 指定的完整 256kb 限制,但我希望有人能够提供解释(如果不能解决此问题)。

json logging aws-lambda amazon-cloudwatch
1个回答
0
投票

    https://nodejs.org/docs/latest-v14.x/api/process.html#process_a_note_on_process_i_o
  • 我在网上搜索了一些可以强制我想要的行为的东西,最终找到了以下解决方案。

process.stdout._handle.setBlocking(true);

这个解决方案有一点警告,我听说它没有被 NodeJS 官方支持,所以它可能会在未来的版本中消失。

如果您像我一样需要 Typescript 版本,请点击下面的链接。

    https://github.com/nodejs/node/issues/1741#issuecomment-1496802107
© www.soinside.com 2019 - 2024. All rights reserved.