Node.js 中的 Amazon Lambda 函数日志记录 - Amazon Lambda
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Node.js 中的 Amazon Lambda 函数日志记录

Amazon Lambda自动代表您监控 Lambda 函数并将日志发送到亚马逊。 CloudWatch您的 Lambda 函数带有 CloudWatch 日志日志组和每个函数实例的日志流。Lambda 运行时环境会将每个调用的详细信息发送到日志流,然后中继函数代码的日志和其他输出。有关更多信息,请参阅将 Amazon CloudWatch 日志与 Amazon Lambda

本页介绍如何从 Lambda 函数的代码生成日志输出,或者如何使用Amazon Command Line Interface、Lambda 控制台或控制台访问日志。 CloudWatch

创建返回日志的函数

要从函数代码输出日志,您可以使用控制台对象的方法或使用写入到 stdoutstderr 的任何日志记录库。以下示例记录环境变量和事件对象的值。

例 index.js 文件 – 日志记录
exports.handler = async function(event, context) { console.log("ENVIRONMENT VARIABLES\n" + JSON.stringify(process.env, null, 2)) console.info("EVENT\n" + JSON.stringify(event, null, 2)) console.warn("Event not processed.") return context.logStreamName }
例 日志格式
START RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac Version: $LATEST 2019-06-07T19:11:20.562Z c793869b-ee49-115b-a5b6-4fd21e8dedac INFO ENVIRONMENT VARIABLES { "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/my-function", "AWS_LAMBDA_LOG_STREAM_NAME": "2019/06/07/[$LATEST]e6f4a0c4241adcd70c262d34c0bbc85c", "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs12.x", "AWS_LAMBDA_FUNCTION_NAME": "my-function", "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "NODE_PATH": "/opt/nodejs/node10/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules", ... } 2019-06-07T19:11:20.563Z c793869b-ee49-115b-a5b6-4fd21e8dedac INFO EVENT { "key": "value" } 2019-06-07T19:11:20.564Z c793869b-ee49-115b-a5b6-4fd21e8dedac WARN Event not processed. END RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac REPORT RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac Duration: 128.83 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 74 MB Init Duration: 166.62 ms XRAY TraceId: 1-5d9d007f-0a8c7fd02xmpl480aed55ef0 SegmentId: 3d752xmpl1bbe37e Sampled: true

Node.js 运行时记录每次调用的 STARTENDREPORT 行。它向函数记录的每个条目添加时间戳、请求 ID 和日志级别。报告行提供了以下详细信息。

REPORT 行数据字段
  • RequestId— 调用的唯一请求 ID。

  • Duration(持续时间)– 函数的处理程序方法处理事件所花费的时间。

  • Billed Duration(计费持续时间)– 针对调用计费的时间量。

  • Memory Size(内存大小)– 分配给函数的内存量。

  • Max Memory Used(最大内存使用量)– 函数使用的内存量。

  • Init Duration(初始持续时间)– 对于提供的第一个请求,为运行时在处理程序方法外部加载函数和运行代码所花费的时间。

  • XRAY TraceId — 对于已跟踪的请求,为Amazon X-Ray跟踪 ID。

  • SegmentId— 对于已跟踪的请求,使用 X-Ray 分段 ID。

  • Sampled(采样)– 对于追踪的请求,为采样结果。

您可以在 Lambda 控制台、 CloudWatch 日志控制台或命令行中查看日志。

在 Node.js 中使用 Lambda 高级日志记录控件

为了让您更好地控制如何捕获、处理和使用函数日志,您可以为支持的 Node.js 运行时系统配置以下日志记录选项:

  • 日志格式 - 为函数日志选择纯文本或结构化的 JSON 格式

  • 日志级别-对于 JSON 格式的日志,选择 Lambda 发送给 Amazon 的日志的详细级别 CloudWatch,例如错误、调试或信息

  • 日志组-选择您的函数将 CloudWatch 日志发送到的日志组

有关这些日志记录选项的更多信息以及如何通过配置来使用函数的说明,请参阅 为您的 Lambda 函数配置高级日志记录控件

要在 Node.js Lambda 函数中使用日志格式和日志级别选项,请参阅以下各节中的指南。

在 Node.js 中使用结构化的 JSON 日志

如果您为函数的日志格式选择 JSON,Lambda 将使用、、、、和的控制台方法将日志输出 CloudWatch 作为结构化 JSON 发送console.warn到结构化 JSON。console.trace console.debug console.log console.info console.error每个 JSON 日志对象包含至少四个键值对和以下键:

  • "timestamp" - 生成日志消息的时间

  • "level" - 分配给消息的日志级别

  • "message" - 日志消息的内容

  • "requestId" - 函数调用的唯一请求 ID

根据函数使用的日志记录方法,此 JSON 对象还可能包含其他密钥对。例如,如果函数通过 console 方法使用多个参数记录错误对象,则 JSON 对象将包含带有键 errorMessageerrorType、和 stackTrace 的额外键值对。

如果您的代码已经使用其他日志记录库(例如 Powertools for Amazon Lambda)来生成 JSON 结构化日志,则无需进行任何更改。Lambda 不会对任何已采用 JSON 编码的日志进行双重编码,因此仍将像以前一样捕获函数的应用程序日志。

有关使用 Powertools for Amazon Lambda 日志记录包在 Node.js 运行时系统中创建 JSON 结构化日志的更多信息,请参阅 Amazon Lambda函数登录 TypeScript

JSON 格式的日志输出示例

以下示例显示了当您将函数的日志格式设置为 JSON 时,如何在 CloudWatch 日志中捕获使用具有单个和多个参数的console方法生成的各种日志输出。

第一个示例使用 console.error 方法输出一个简单的字符串。

例 Node.js 日志记录代码
export const handler = async (event) => { console.error("This is a warning message"); ... }
例 JSON 日志记录
{ "timestamp":"2023-11-01T00:21:51.358Z", "level":"ERROR", "message":"This is a warning message", "requestId":"93f25699-2cbf-4976-8f94-336a0aa98c6f" }

您还可以使用 console 方法中的单个或多个参数输出更复杂的结构化日志消息。在下一个示例中,您可以使用 console.log 的单个参数输出两个键值对。请注意,Lambda 发送到 CloudWatch 日志的 JSON 对象中的"message"字段未进行字符串化。

例 Node.js 日志记录代码
export const handler = async (event) => { console.log({data: 12.3, flag: false}); ... }
例 JSON 日志记录
{ "timestamp": "2023-12-08T23:21:04.664Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": { "data": 12.3, "flag": false } }

在下一个示例中,您可以再次使用 console.log 方法创建日志输出。这次,该方法采用两个参数,即一个包含两个键值对的映射和一个标识字符串。请注意,在本例中,由于您提供了两个参数,因此 Lambda 会对 "message" 字段进行字符串化。

例 Node.js 日志记录代码
export const handler = async (event) => { console.log('Some object - ', {data: 12.3, flag: false}); ... }
例 JSON 日志记录
{ "timestamp": "2023-12-08T23:21:04.664Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": "Some object - { data: 12.3, flag: false }" }

Lambda 为使用 console.log 生成的输出分配日志级别 INFO。

最后一个示例显示了如何使用这些console方法将错误对象输出 CloudWatch 到 Logs。请注意,当您使用多个参数记录错误对象时,Lambda 会将字段 errorMessageerrorTypestackTrace 添加到日志输出中。要了解有关 Node.js 中函数错误的更多信息,请参阅 Node.js 中的 Amazon Lambda 函数错误

例 Node.js 日志记录代码
export const handler = async (event) => { let e1 = new ReferenceError("some reference error"); let e2 = new SyntaxError("some syntax error"); console.log(e1); console.log("errors logged - ", e1, e2); };
例 JSON 日志记录
{ "timestamp": "2023-12-08T23:21:04.632Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": { "errorType": "ReferenceError", "errorMessage": "some reference error", "stackTrace": [ "ReferenceError: some reference error", " at Runtime.handler (file:///var/task/index.mjs:3:12)", " at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)" ] } } { "timestamp": "2023-12-08T23:21:04.646Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": "errors logged - ReferenceError: some reference error\n at Runtime.handler (file:///var/task/index.mjs:3:12)\n at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29) SyntaxError: some syntax error\n at Runtime.handler (file:///var/task/index.mjs:4:12)\n at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)", "errorType": "ReferenceError", "errorMessage": "some reference error", "stackTrace": [ "ReferenceError: some reference error", " at Runtime.handler (file:///var/task/index.mjs:3:12)", " at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)" ] }

记录多种错误类型时,会从提供给 console 方法的第一个错误类型中提取额外的 errorMessageerrorTypestackTrace 字段。

使用带有结构化的 JSON 日志的嵌入式指标格式(EMF)客户端库

Amazon 提供了用于 Node.js 的开源客户端库,可供您用来创建嵌入式指标格式(EMF)日志。如果您有使用这些库的现有函数,并且将函数的日志格式更改为 JSON,则 CloudWatch 可能无法再识别您的代码发出的指标。

如果您的代码当前直接使用console.log或使用 Powertools for Amazon Lambda (TypeScript) 发出 EMF 日志,那么如果您 CloudWatch 将函数的日志格式更改为 JSON,也将无法解析这些日志。

重要

为确保函数的 EMF 日志能够继续被正确解析,请将适用于Amazon Lambda库的 CloudWatch EMF 和 Powertools 更新到最新版本。如果切换到 JSON 日志格式,我们还建议您进行测试以确保与函数的嵌入式指标兼容。如果您的代码直接使用 console.log 发出 EMF 日志,请更改您的代码以将这些指标直接输出到 stdout,如以下示例代码所示。

例 向 stdout 发送嵌入式指标的代码
process.stdout.write(JSON.stringify( { "_aws": { "Timestamp": Date.now(), "CloudWatchMetrics": [{ "Namespace": "lambda-function-metrics", "Dimensions": [["functionVersion"]], "Metrics": [{ "Name": "time", "Unit": "Milliseconds", "StorageResolution": 60 }] }] }, "functionVersion": "$LATEST", "time": 100, "requestId": context.awsRequestId } ) + "\n")

在 Node.js 中使用日志级别筛选

为了让 Amazon Lambda 根据日志级别筛选应用程序日志,您的函数必须使用 JSON 格式的日志。您可以通过两种方式实现这一点:

  • 使用标准控制台方法创建日志输出,并将您的函数配置为使用 JSON 日志格式。然后 Amazon Lambda 使用 在 Node.js 中使用结构化的 JSON 日志 中所述 JSON 对象中的“级别”键值对筛选日志输出。要了解如何配置函数的日志格式,请参阅 为您的 Lambda 函数配置高级日志记录控件

  • 使用其他日志记录库或方法在代码中创建 JSON 结构化日志,其中包含定义日志输出级别的“级别”键值对。例如,您可以使用 Powertools for Amazon Lambda 通过代码生成 JSON 结构化日志输出。要了解有关在 Node.js 运行时系统中使用 Powertools 的更多信息,请参阅 Amazon Lambda函数登录 TypeScript

    要让 Lambda 筛选函数的日志,还必须在 JSON 日志输出中包含一个 "timestamp" 键值对。必须以有效的 RFC 3339 时间戳格式指定时间。如果您未提供有效的时间戳,Lambda 将为日志分配 INFO 级别并为您添加时间戳。

将函数配置为使用日志级别筛选时,可以从以下选项中选择要发送Amazon Lambda到 CloudWatch 日志的日志级别:

日志级别 标准使用情况
TRACE(最详细) 用于跟踪代码执行路径的最精细信息
调试 系统调试的详细信息
信息 记录函数正常运行情况的消息
警告 有关潜在错误的消息,如果不加以解决,这些错误可能会导致意外行为
ERROR 有关会阻碍代码按预期执行的问题的消息
FATAL(最简略) 有关导致应用程序停止运行的严重错误的消息

Lambda 将选定级别及更低级别的日志发送到。 CloudWatch例如,如果您将日志级别配置为 WARN,Lambda 将发送与 WARN、ERROR 和 FATAL 级别相对应的日志。

使用 Lambda 控制台

调用 Lambda 函数后,您可以使用 Lambda 控制台查看日志输出。

如果可以在嵌入式代码编辑器中测试代码,则可以在执行结果中找到日志。使用控制台测试功能调用函数时,可以在详细信息部分找到日志输出

使用控制 CloudWatch 台

您可以使用亚马逊 CloudWatch 控制台查看所有 Lambda 函数调用的日志。

在 CloudWatch 控制台上查看日志
  1. 在 CloudWatch 控制台上打开日志组页面

  2. 为您的函数选择日志组 (/aws/lambda/ your-function-name)。

  3. 创建日志流。

每个日志流对应一个函数实例。日志流会在您更新 Lambda 函数以及创建更多实例来处理多个并发调用时显示。要查找特定调用的日志,建议您使用 Amazon X-Ray 检测函数。X-Ray 会在追踪中记录有关请求和日志流的详细信息。

如需使用将日志和跟踪与 X-Ray 相关联的示例应用程序,请参阅 Amazon Lambda 错误处理器示例应用程序

使用 Amazon Command Line Interface (Amazon CLI)

Amazon CLI 是一种开源工具,让您能够在命令行 Shell 中使用命令与 Amazon 服务进行交互。要完成本节中的步骤,您必须满足以下条件:

您可以通过 Amazon CLI,使用 --log-type 命令选项检索调用的日志。响应包含一个 LogResult 字段,其中包含多达 4KB 来自调用的 base64 编码日志。

例 检索日志 ID

以下示例说明如何从 LogResult 字段中检索名为 my-function 的函数的日志 ID

aws lambda invoke --function-name my-function out --log-type Tail

您应看到以下输出:

{ "StatusCode": 200, "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...", "ExecutedVersion": "$LATEST" }
例 解码日志

在同一命令提示符下,使用 base64 实用程序解码日志。以下示例说明如何为 my-function 检索 base64 编码的日志。

aws lambda invoke --function-name my-function out --log-type Tail \ --query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode

如果使用 cli-binary-format 版本 2,则 Amazon CLI 选项是必需的。要将其设为默认设置,请运行 aws configure set cli-binary-format raw-in-base64-out。有关更多信息,请参阅版本 2 的 Amazon Command Line Interface 用户指南中的 Amazon CLI 支持的全局命令行选项

您应看到以下输出:

START RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Version: $LATEST "AWS_SESSION_TOKEN": "AgoJb3JpZ2luX2VjELj...", "_X_AMZN_TRACE_ID": "Root=1-5d02e5ca-f5792818b6fe8368e5b51d50;Parent=191db58857df8395;Sampled=0"",ask/lib:/opt/lib", END RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 REPORT RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Duration: 79.67 ms Billed Duration: 80 ms Memory Size: 128 MB Max Memory Used: 73 MB

base64 实用程序在 Linux、macOS 和 Ubuntu on Windows 上可用。macOS 用户可能需要使用 base64 -D

例 get-logs.sh 脚本

在同一命令提示符下,使用以下脚本下载最后五个日志事件。此脚本使用 sed 从输出文件中删除引号,并休眠 15 秒以等待日志可用。输出包括来自 Lambda 的响应,以及来自 get-log-events 命令的输出。

复制以下代码示例的内容并将其作为 get-logs.sh 保存在 Lambda 项目目录中。

如果使用 cli-binary-format 版本 2,则 Amazon CLI 选项是必需的。要将其设为默认设置,请运行 aws configure set cli-binary-format raw-in-base64-out。有关更多信息,请参阅版本 2 的 Amazon Command Line Interface 用户指南中的 Amazon CLI 支持的全局命令行选项

#!/bin/bash aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"key": "value"}' out sed -i'' -e 's/"//g' out sleep 15 aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name stream1 --limit 5
例 macOS 和 Linux(仅限)

在同一命令提示符下,macOS 和 Linux 用户可能需要运行以下命令以确保脚本可执行。

chmod -R 755 get-logs.sh
例 检索最后五个日志事件

在同一命令提示符下,运行以下脚本以获取最后五个日志事件。

./get-logs.sh

您应看到以下输出:

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" } { "events": [ { "timestamp": 1559763003171, "message": "START RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf Version: $LATEST\n", "ingestionTime": 1559763003309 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tENVIRONMENT VARIABLES\r{\r \"AWS_LAMBDA_FUNCTION_VERSION\": \"$LATEST\",\r ...", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tEVENT\r{\r \"key\": \"value\"\r}\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "END RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "REPORT RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\tDuration: 26.73 ms\tBilled Duration: 27 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n", "ingestionTime": 1559763018353 } ], "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795", "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080" }

删除日志

删除函数时,日志组不会自动删除。要避免无限期存储日志,请删除日志组,或配置一个保留期,在该保留期之后,日志将自动删除。