

# 查看 Lambda 函数的 CloudWatch 日志
<a name="monitoring-cloudwatchlogs-view"></a>

您可以使用 Lambda 控制台、CloudWatch 控制台或 AWS Command Line Interface（AWS CLI）查看 Lambda 函数的 Amazon CloudWatch Logs。按照以下各节中的说明访问函数的日志。

## 使用 CloudWatch Logs Live Tail 流式处理函数日志
<a name="monitoring-live-tail"></a>

Amazon CloudWatch Logs Live Tail 通过直接在 Lambda 控制台中显示新日志事件的流式列表，来帮助您快速对函数进行问题排查。您可以通过 Lambda 函数实时地查看和筛选提取的日志，帮助您快速检测并解决问题。

**注意**  
Live Tail 会话按会话使用时间每分钟产生费用。有关定价的更多信息，请参阅 [Amazon CloudWatch 定价](https://aws.amazon.com/cloudwatch/pricing/)。

### 比较 Live Tail 和 --log-type Tail
<a name="live-tail-logtype"></a>

CloudWatch Logs Live Tail 和 Lambda API 中的 [LogType: Tail](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html#lambda-Invoke-request-LogType) 选项（AWS CLI 中的 `--log-type Tail`）之间有多项差异：
+ `--log-type Tail` 仅返回调用日志的前 4 KB。Live Tail 不具备此限制，并且每秒最多可以接收 500 个日志事件。
+ `--log-type Tail` 捕获并发送带有响应的日志，这可能会影响函数的响应延迟。Live Tail 不会影响函数响应延迟。
+ `--log-type Tail` 仅支持同步调用。Live Tail 适用于同步和异步调用。

**注意**  
[Lambda 托管实例](lambda-managed-instances.md)不支持 `--log-type Tail` 选项。使用 CloudWatch Logs Live Tail 或直接查询 CloudWatch Logs 来查看托管实例函数的日志。

### 权限
<a name="live-tail-permissions"></a>

启动和停止 CloudWatch Logs Live Tail 会话需要以下权限：
+ `logs:DescribeLogGroups`
+ `logs:StartLiveTail`
+ `logs:StopLiveTail`

### 在 Lambda 控制台中启动 Live Tail 会话
<a name="live-tail-console"></a>

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择此函数的名称。

1. 选择**测试**选项卡。

1. 在**测试事件**窗格中，选择 **CloudWatch Logs Live Tail**。

1. 对于**选择日志组**，默认情况下会选择该函数的日志组。一次最多可选择 5 个日志组。

1. （可选）要仅显示包含某些单词或其他字符串的日志事件，请在**添加筛选模式**框中输入词或字符串。筛选字段不区分大小写。您可以在此字段中包含多个术语和模式运算符，包含正则表达式（regex）。有关更多信息，请参阅《Amazon CloudWatch Logs User Guide》**中的 [Filter pattern syntax](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html)。

1. 选择**启动**。匹配的日志事件开始出现在窗口中。

1. 要停止 Live Tail 会话，请选择**停止**。
**注意**  
Live Tail 会话会在处于非活动状态 15 分钟后或 Lambda 控制台会话超时后自动停止。

## 使用控制台访问函数日志
<a name="monitoring-cloudwatchlogs-console"></a>

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择一个函数。

1. 选择**监控**选项卡。

1. 选择**查看 CloudWatch 日志**打开 CloudWatch 控制台。

1. 向下滚动，选择要查看的函数调用的**日志流**。  
![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/log-stream.png)

Lambda 函数的每个实例都具有一个专用的日志流。如果函数纵向扩展，每个并发实例都具有自己的日志流。每次创建新的执行环境来响应调用时，都会生成新的日志流。日志流的命名约定是：

```
YYYY/MM/DD[Function version][Execution environment GUID]
```

单一执行环境在生命周期内写入同一个日志流。日志流包含来自该执行环境的消息，以及您的 Lambda 函数代码的任何输出。每条消息都带有时间戳，包括您的自定义日志。即使您的函数不记录代码的任何输出，每次调用也会生成三个最小的日志语句（START、END 和 REPORT）：

![\[监控可观测性图 3\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/monitoring-observability-figure-3.png)


这些日志显示：
+  **RequestId** – 这是每个请求生成的唯一 ID。如果 Lambda 函数重试请求，则此 ID 不会更改，且会显示在每次后续重试的日志中。
+  **开始/结束** – 这些为单一调用添加了书签，因此它们之间的每个日志行都属于同一调用。
+  **持续时间** – 处理程序函数的总调用时间，不包括 `INIT` 代码。
+  **计费持续时间** – 为计费目的应用舍入逻辑。
+  **内存大小** – 分配给函数的内存量。
+  **最大已用内存**：调用期间使用的最大内存量。
+  **初始化持续时间** – 在主处理程序之外运行 `INIT` 代码部分所花费的时间。

## 使用 AWS CLI 访问日志
<a name="monitoring-cloudwatchlogs-cli"></a>

AWS CLI 是一种开源工具，让您能够在命令行 Shell 中使用命令与 AWS 服务进行交互。要完成本节中的步骤，您必须拥有 [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

您可以通过 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)，使用 `--log-type` 命令选项检索调用的日志。响应包含一个 `LogResult` 字段，其中包含多达 4KB 来自调用的 base64 编码日志。

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

```
aws lambda invoke --function-name my-function out --log-type Tail
```
您应看到以下输出：  

```
{
    "StatusCode": 200,
    "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...",
    "ExecutedVersion": "$LATEST"
}
```

**Example 解码日志**  
在同一命令提示符下，使用 `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，则 AWS CLI 选项是必需的。要将其设为默认设置，请运行 `aws configure set cli-binary-format raw-in-base64-out`。有关更多信息，请参阅*版本 2 的 AWS Command Line Interface 用户指南*中的 [AWS CLI 支持的全局命令行选项](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。  
您应看到以下输出：  

```
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](https://docs.microsoft.com/en-us/windows/wsl/install-win10) 上可用。macOS 用户可能需要使用 `base64 -D`。



**Example get-logs.sh 脚本**  
在同一命令提示符下，使用以下脚本下载最后五个日志事件。此脚本使用 `sed` 从输出文件中删除引号，并休眠 15 秒以等待日志可用。输出包括来自 Lambda 的响应，以及来自 `get-log-events` 命令的输出。  
复制以下代码示例的内容并将其作为 `get-logs.sh` 保存在 Lambda 项目目录中。  
如果使用 **cli-binary-format** 版本 2，则 AWS CLI 选项是必需的。要将其设为默认设置，请运行 `aws configure set cli-binary-format raw-in-base64-out`。有关更多信息，请参阅*版本 2 的 AWS Command Line Interface 用户指南*中的 [AWS CLI 支持的全局命令行选项](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。  

```
#!/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
```

**Example macOS 和 Linux（仅限）**  
在同一命令提示符下，macOS 和 Linux 用户可能需要运行以下命令以确保脚本可执行。  

```
chmod -R 755 get-logs.sh
```

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

```
./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"
}
```

## 解析日志和结构化日志
<a name="querying-logs"></a>

借助 CloudWatch Logs Insights，您可以使用专用[查询语法](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html)搜索和分析日志数据。它对多个日志组执行查询，并使用 [glob](https://en.wikipedia.org/wiki/Glob_(programming)) 和[正则表达式](https://en.wikipedia.org/wiki/Regular_expression)模式匹配提供功能强大的筛选功能。

您可以通过在 Lambda 函数中实施结构化日志记录来利用这些功能。结构化日志将您的日志组织成预定义的格式，便于查询。使用日志级别是生成便于筛选的日志的重要第一步，这些文件将信息性消息与警告或错误区分开来。例如，请考虑以下 Node.js 代码：

```
exports.handler = async (event) => {
    console.log("console.log - Application is fine")
    console.info("console.info - This is the same as console.log")
    console.warn("console.warn - Application provides a warning")
    console.error("console.error - An error occurred")
}
```

生成的 CloudWatch 日志文件包含一个单独的字段，用于指定日志级别：

![\[监控可观测性图 10\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/monitoring-observability-figure-10.png)


然后，CloudWatch Logs Insights 查询可以按日志级别进行筛选。例如，要仅查询错误，可以使用以下查询：

```
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
```

### JSON 结构化日志记录
<a name="querying-logs-json"></a>

JSON 通常用于为应用程序日志提供结构。在以下示例中，日志已转换为 JSON 以输出三个不同的值：

![\[监控可观测性图 11\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/monitoring-observability-figure-11.png)


CloudWatch Logs Insights 功能可自动发现 JSON 输出中的值并将消息解析为字段，而无需自定义 glob 或正则表达式。通过使用 JSON 结构的日志，以下查询查找上传的文件大于 1MB、上传时间超过 1 秒且调用不是冷启动的调用：

```
fields @message
| filter @message like /INFO/
| filter uploadedBytes > 1000000
| filter uploadTimeMS > 1000
| filter invocation != 1
```

此查询可能生成以下结果：

![\[监控可观测性图 12\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/monitoring-observability-figure-12.png)


在 JSON 中发现的字段会自动填充到右侧的*已发现字段*菜单中。Lambda 服务发出的标准字段以“@”为前缀，您可以用相同的方式查询这些字段。Lambda 日志始终包含字段 @timestamp、@logStream、@message、@requestId、@duration、@billedDuration、@type、@maxMemoryUsed 和 @memorySize。如果为某个函数启用了 X-Ray，日志还会包含 @xrayTraceId 和 @xraySegmentId。

当 Amazon S3、Amazon SQS 或 Amazon EventBridge 之类的 AWS 事件源调用您的函数时，整个事件将作为 JSON 对象输入提供给该函数。通过在函数的第一行记录此事件，您随后就可以使用 CloudWatch Logs Insights 查询任何嵌套字段。

### 实用的 Insights 查询
<a name="useful-logs-queries"></a>

下表显示了可用于监控 Lambda 函数的 Insights 查询示例。


| 说明 |  查询语法示例 | 
| --- | --- | 
|  最后 100 个错误  |  

```
 fields Timestamp, LogLevel, Message
 \| filter LogLevel == "ERR"
 \| sort @timestamp desc
 \| limit 100
```  | 
|  计费最高的前 100 次调用  |  

```
filter @type = "REPORT"
\| fields @requestId, @billedDuration
\| sort by @billedDuration desc
\| limit 100
```  | 
|  冷启动占总调用次数的百分比  |  

```
filter @type = "REPORT"
\| stats sum(strcontains(@message, "Init Duration"))/count(*) * 100 as
  coldStartPct, avg(@duration)
  by bin(5m)
```  | 
|  Lambda 持续时间的百分位数报告  |  

```
filter @type = "REPORT"
\| stats
    avg(@billedDuration) as Average,
    percentile(@billedDuration, 99) as NinetyNinth,
    percentile(@billedDuration, 95) as NinetyFifth,
    percentile(@billedDuration, 90) as Ninetieth
    by bin(30m)
```  | 
|  Lambda 内存使用量的百分位数报告  |  

```
filter @type="REPORT"
\| stats avg(@maxMemoryUsed/1024/1024) as mean_MemoryUsed,
    min(@maxMemoryUsed/1024/1024) as min_MemoryUsed,
    max(@maxMemoryUsed/1024/1024) as max_MemoryUsed,
    percentile(@maxMemoryUsed/1024/1024, 95) as Percentile95
```  | 
|  使用 100% 分配内存的调用  |  

```
filter @type = "REPORT" and @maxMemoryUsed=@memorySize
\| stats
    count_distinct(@requestId)
    by bin(30m)
```  | 
|  各次调用的平均内存使用量  |  

```
avgMemoryUsedPERC,
    avg(@billedDuration) as avgDurationMS
    by bin(5m)
```  | 
|  内存统计数据的可视化  |  

```
filter @type = "REPORT"
\| stats
    max(@maxMemoryUsed / 1024 / 1024) as maxMemMB,
    avg(@maxMemoryUsed / 1024 / 1024) as avgMemMB,
    min(@maxMemoryUsed / 1024 / 1024) as minMemMB,
    (avg(@maxMemoryUsed / 1024 / 1024) / max(@memorySize / 1024 / 1024)) * 100 as avgMemUsedPct,
    avg(@billedDuration) as avgDurationMS
    by bin(30m)
```  | 
|  Lambda 退出时的调用  |  

```
filter @message like /Process exited/
\| stats count() by bin(30m)
```  | 
|  超时的调用  |  

```
filter @message like /Task timed out/
\| stats count() by bin(30m)
```  | 
|  延迟报告  |  

```
filter @type = "REPORT"
\| stats avg(@duration), max(@duration), min(@duration)
  by bin(5m)
```  | 
|  内存过度预调配  |  

```
filter @type = "REPORT"
\| stats max(@memorySize / 1024 / 1024) as provisonedMemMB,
        min(@maxMemoryUsed / 1024 / 1024) as smallestMemReqMB,
        avg(@maxMemoryUsed / 1024 / 1024) as avgMemUsedMB,
        max(@maxMemoryUsed / 1024 / 1024) as maxMemUsedMB,
        provisonedMemMB - maxMemUsedMB as overProvisionedMB
```  | 

## 日志可视化和控制面板
<a name="monitoring-logs-visualization"></a>

对于任何 CloudWatch Logs Insights 查询，您可以将结果导出为 markdown 或 CSV 格式。在某些情况下，如果至少有一个聚合函数，则[根据查询创建可视化](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_Insights-Visualizing-Log-Data.html)可能会更有用。`stats` 函数允许您定义聚合和分组。

以前的 *logInsightsJSON* 示例根据上传大小和上传时间进行了筛选，且排除了首次调用。这产生了一个数据表。为了监控生产系统，可视化最小、最大和平均文件大小以查找异常值可能更有用。为此，请使用带有所需聚合的 stats 函数，然后按时间值（例如每分钟）进行分组：

例如，请考虑以下查询。这与 [JSON 结构化日志记录](#querying-logs-json) 部分中的示例查询相同，但具有其他聚合函数：

```
fields @message
| filter @message like /INFO/
| filter uploadedBytes > 1000000
| filter uploadTimeMS > 1000
| filter invocation != 1
| stats min(uploadedBytes), avg(uploadedBytes), max(uploadedBytes) by bin (1m)
```

我们之所以加入这些聚合，是因为通过可视化最小、最大和平均文件大小来查找异常值可能会更有用。您可以在**可视化**选项卡中查看结果：

![\[监控可观测性图 14\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/monitoring-observability-figure-14.png)


构建完可视化后，您可以选择将图表添加到 CloudWatch 控制面板。要执行此操作，请选择可视化上方的**添加到控制面板**。这会将查询添加为小组件，并允许您选择自动刷新间隔，从而更轻松地持续监控结果：

![\[监控可观测性图 15\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/monitoring-observability-figure-15.png)
