

# 使用 Lambda 日志 API
<a name="runtimes-logs-api"></a>

**重要**  
Lambda 遥测 API 取代 Lambda Logs API。**尽管 Logs API 仍然功能完备，但我们建议您今后仅使用遥测 API。**您可以使用遥测 API 或 Logs API 为扩展订阅遥测流。使用其中一个 API 进行订阅后，任何使用其他 API 进行订阅的尝试都会返回错误。

**Lambda 托管实例不支持日志 API**  
Lambda 托管实例不支持日志 API。如果您正在使用托管实例函数，请改用[遥测 API](telemetry-api.md)。遥测 API 为从您的 Lambda 函数中收集和处理遥测数据提供增强功能。

Lambda 会自动捕获运行时日志并将其流式传输到 Amazon CloudWatch。此日志流包含函数代码和扩展生成的日志，以及 Lambda 作为函数调用的一部分生成的日志。

[Lambda](runtimes-extensions-api.md) 扩展可以使用 Lambda Runtime Logs API 从 Lambda [执行环境](lambda-runtime-environment.md)中直接订阅日志流。Lambda 将日志流式传输到扩展，便于扩展处理、筛选日志并将其发送到首选目标。

![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/logs-api-concept-diagram.png)


Logs API 允许扩展订阅三种不同的日志流：
+ Lambda 函数生成并写入 `stdout` 或 `stderr` 的函数日志。
+ 扩展代码生成的扩展日志。
+ Lambda 平台日志，记录与调用和扩展相关的事件和错误。

**注意**  
Lambda 会将所有日志发送到 CloudWatch，即使扩展订阅了一个或多个日志流也是如此。

**Topics**
+ [订阅接收日志](#runtimes-logs-api-subscribing)
+ [内存使用量](#runtimes-logs-api-memory)
+ [目标协议](#runtimes-logs-api-dest)
+ [缓冲配置](#runtimes-logs-api-buffering)
+ [示例订阅](#runtimes-logs-api-subs-example)
+ [Logs API 的示例代码](#runtimes-logs-api-samples)
+ [Logs API 参考](#runtimes-logs-api-ref)
+ [日志消息](#runtimes-logs-api-msg)

## 订阅接收日志
<a name="runtimes-logs-api-subscribing"></a>

Lambda 扩展可以通过向 Logs API 发送订阅请求来订阅接收日志。

要订阅接收日志，则需要扩展标识符 (`Lambda-Extension-Identifier`)。首先，[注册扩展](runtimes-extensions-api.md#extensions-registration-api-a)以接收扩展标识符。然后，在[初始化](lambda-runtime-environment.md#runtimes-lifecycle-ib)期间订阅 Logs API。初始化阶段完成后，Lambda 不会处理订阅请求。

**注意**  
Logs API 订阅是幂等的。重复的订阅请求不会导致重复订阅。

## 内存使用量
<a name="runtimes-logs-api-memory"></a>

内存使用量随着订阅者数量的增加而线性增加。订阅会消耗内存资源，因为每个订阅都会打开一个新的内存缓冲区来存储日志。为了帮助优化内存使用量，您可以调整[缓冲配置](#runtimes-logs-api-buffering)。缓冲区内存使用量计入执行环境中的总内存消耗量。

## 目标协议
<a name="runtimes-logs-api-dest"></a>

您可以选择以下协议之一来接收日志：

1. **HTTP**（推荐）– Lambda 会将日志作为 JSON 格式的记录数组传送到本地 HTTP 端点 (`http://sandbox.localdomain:${PORT}/${PATH}`)。`$PATH` 参数是可选的。请注意，只支持 HTTP，不支持 HTTPS。您可以选择通过 PUT 或 POST 来接收日志。

1. **TCP** – Lambda 会将日志以[换行符分隔的 JSON (NDJSON) 格式](https://github.com/ndjson/ndjson-spec)传送到 TCP 端口。

我们建议使用 HTTP 而不是 TCP。使用 TCP 时，Lambda 平台无法在其将日志传送到应用层时进行确认。因此，如果扩展崩溃，日志可能会丢失。HTTP 则无此限制。

我们还建议在订阅接收日志之前设置本地 HTTP 侦听器或 TCP 端口。在安装期间，请注意以下事项：
+ Lambda 只会将日志发送到执行环境内的目标。
+ 如果没有侦听器，或者 POST 或 PUT 请求导致错误，Lambda 会尝试重试发送日志（退避尝试）。如果日志订阅者崩溃，它会在 Lambda 重新启动执行环境后继续接收日志。
+ Lambda 会预留端口 9001。没有其他端口号限制或建议。

## 缓冲配置
<a name="runtimes-logs-api-buffering"></a>

Lambda 可以缓冲日志并将其发送给订阅者。您可以通过指定以下可选字段在订阅请求中配置此行为。请注意，Lambda 对未指定的字段使用默认值。
+ **timeoutMs** – 缓冲批的最长时间（以毫秒为单位）。默认值：1,000。最低：25。最大值：30,000。
+ **maxBytes** – 在内存中缓冲的最大大小（以字节为单位）。默认值：262,144。最小值：262,144。最大值：1,048,576。
+ **maxItems** – 在内存中缓冲的最大事件数。默认值：10,000。最小值：1,000。最大值：10,000。

在缓冲配置期间，请注意以下几点：
+ 如果任何输入流关闭（例如，运行时崩溃），Lambda 会刷新日志。
+ 在订阅请求中，每个订阅者都可以指定不同的缓冲配置。
+ 考虑读取数据所需的缓冲区大小。预计最多可接收 `2*maxBytes+metadata` 的有效负载，其中，`maxBytes` 在订阅请求中配置。例如，Lambda 会将以下元数据字节添加到每条记录：

  ```
  {
  "time": "2020-08-20T12:31:32.123Z",
  "type": "function",
  "record": "Hello World"
  }
  ```
+ 如果订阅者处理传入日志的速度不够快，Lambda 可能会删除日志以保持内存利用率限制。为指示丢弃记录数，Lambda 会发送一个 `platform.logsDropped` 日志。有关更多信息，请参阅 [Lambda：并非所有我的函数的日志都会出现](troubleshooting-execution.md#troubleshooting-execution-missinglogs)。

## 示例订阅
<a name="runtimes-logs-api-subs-example"></a>

以下示例显示订阅平台和函数日志的请求。

```
PUT http://${AWS_LAMBDA_RUNTIME_API}/2020-08-15/logs HTTP/1.1
{ "schemaVersion": "2020-08-15",
  "types": [
      "platform",
      "function"
    ],
  "buffering": {
      "maxItems": 1000,
      "maxBytes": 262144,
      "timeoutMs": 100
    },
  "destination": {
    "protocol": "HTTP",
    "URI": "http://sandbox.localdomain:8080/lambda_logs"
  }
}
```

如果请求成功，订阅者将收到一条 HTTP 200 成功响应。

```
HTTP/1.1 200 OK
"OK"
```

## Logs API 的示例代码
<a name="runtimes-logs-api-samples"></a>

有关显示如何将日志发送到自定义目标的示例代码，请参阅 AWS Lambda 计算博客上的[使用 AWS 扩展将日志发送到自定义目标](https://aws.amazon.com/blogs/compute/using-aws-lambda-extensions-to-send-logs-to-custom-destinations/)。

有关显示如何开发基本 Lambda 扩展和订阅 Logs API 的 Python 和 Go 代码示例，请参阅AWS示例 GitHub 存储库上的 [AWS Lambda扩展](https://github.com/aws-samples/aws-lambda-extensions)。有关构建 Lambda 扩展的更多信息，请参阅 [使用 Lambda 扩展 API 创建扩展](runtimes-extensions-api.md)。

## Logs API 参考
<a name="runtimes-logs-api-ref"></a>

您可以从 `AWS_LAMBDA_RUNTIME_API` 环境变量中检索 Logs API 终端节点。要发送 API 请求，请在 API 路径前使用前缀 `2020-08-15/`。例如：

```
http://${AWS_LAMBDA_RUNTIME_API}/2020-08-15/logs
```

Logs API 版本 **2020-08-15** 的 OpenAPI 规范可从此处获得：[logs-api-request.zip](samples/logs-api-request.zip)

### Subscribe
<a name="runtimes-logs-api-ref-a"></a>

要订阅一个或多个在 Lambda 执行环境中可用的日志流，扩展会发送 Subscribe API 请求。

**路径** – `/logs`

**方法** – **PUT**

**主体参数**

`destination`请参阅 [目标协议](#runtimes-logs-api-dest)。必需：是。类型：字符串。

`buffering`请参阅 [缓冲配置](#runtimes-logs-api-buffering)。必需：否 类型：字符串。

`types` – 要接收的日志类型的数组。必需：是。类型：字符串数组。有效值："platform"、"function"、"extension"。

`schemaVersion` – 必需：否。默认值：“2020-08-15”。设置为“2021-03-18”以便扩展接收 [`platform.runtimeDone`](#runtimes-logs-api-ref-done) 消息。

****响应参数****

提供适用于 HTTP 和 TCP 协议的订阅响应版本 **2020-08-15** 的 OpenAPI 规范：
+ HTTP：[logs-api-http-response.zip](samples/logs-api-http-response.zip)
+ TCP：[logs-api-tcp-response.zip](samples/logs-api-tcp-response.zip)

****响应代码****
+ 200 – 已成功完成请求
+ 202 – 已接受请求。在本地测试期间响应订阅请求。
+ 4XX – 错误请求
+ 500 – 服务错误

如果请求成功，订阅者将收到一条 HTTP 200 成功响应。

```
HTTP/1.1 200 OK
"OK"
```

如果请求失败，订阅者将收到一条错误响应。例如：

```
HTTP/1.1 400 OK
{
    "errorType": "Logs.ValidationError",
    "errorMessage": URI port is not provided; types should not be empty"
}
```

## 日志消息
<a name="runtimes-logs-api-msg"></a>

Logs API 允许扩展订阅三种不同的日志流：
+ 函数 – Lambda 函数生成并写入 `stdout` 或 `stderr` 的日志。
+ 扩展 – 扩展代码生成的日志。
+ 平台 – 运行时平台生成的平台日志，用于记录与调用和扩展相关的事件和错误。

**Topics**
+ [函数日志](#runtimes-logs-api-msg-function)
+ [扩展日志](#runtimes-logs-api-msg-extension)
+ [平台日志](#runtimes-logs-api-msg-platform)

### 函数日志
<a name="runtimes-logs-api-msg-function"></a>

Lambda 函数和内部扩展会生成函数日志并将其写入 `stdout` 或 `stderr`。

以下示例显示了函数日志消息的格式。\$1 "time": "2020-08-20T12:31:32.123Z", "type": "function", "record": Stack trace:\$1n\$1my-function (line 10)\$1n" \$1 

### 扩展日志
<a name="runtimes-logs-api-msg-extension"></a>

扩展可以生成扩展日志。日志格式与函数日志的格式相同。

### 平台日志
<a name="runtimes-logs-api-msg-platform"></a>

Lambda 会为平台事件（例如 `platform.start`、`platform.end` 和 `platform.fault`）生成日志消息。

或者，您可以订阅 ** 2021-03-18 ** 版本的 Logs API 架构，其中包括 `platform.runtimeDone` 日志消息。

#### 示例平台日志消息
<a name="runtimes-logs-api-examples"></a>

以下示例显示了平台开始日志和平台结束日志。这些日志指定了 requestId 指定的调用的调用开始时间和调用结束时间。

```
{     
    "time": "2020-08-20T12:31:32.123Z",
    "type": "platform.start",
    "record": {"requestId": "6f7f0961f83442118a7af6fe80b88d56"}   
}
{
    "time": "2020-08-20T12:31:32.123Z",
    "type": "platform.end",
    "record": {"requestId": "6f7f0961f83442118a7af6fe80b88d56"}   
}
```

**platform.initRuntimeDone** 日志消息显示 `Runtime init` 子阶段的状态，该子阶段是[初始化生命周期阶段](lambda-runtime-environment.md#runtimes-lifecycle-ib)的一部分。`Runtime init` 成功后，运行时会发送 `/next` 运行时 API 请求（针对 `on-demand` 和 `provisioned-concurrency` 初始化类型）或 `restore/next`（针对 `snap-start` 初始化类型）。以下示例显示适用于 `snap-start` 初始化类型的成功 **platform.initRuntimeDone** 日志消息。

```
{
  "time":"2022-07-17T18:41:57.083Z",
  "type":"platform.initRuntimeDone",
  "record":{
      "initializationType":"snap-start",
      "status":"success"
  }
}
```

**platform.initReport** 日志消息显示该 `Init` 阶段的持续时间以及该阶段已计费的毫秒数。当初始化类型为 `provisioned-concurrency` 时，Lambda 会在调用期间发送此消息。当初始化类型为 `snap-start` 时，Lambda 会在还原快照后发送此消息。以下示例显示适用于 `snap-start` 初始化类型的 **platform.initReport** 日志消息。

```
{
  "time":"2022-07-17T18:41:57.083Z",
  "type":"platform.initReport",
  "record":{
      "initializationType":"snap-start",
      "metrics":{
          "durationMs":731.79,
          "billedDurationMs":732
          }
  }
}
```

平台报告日志包含有关 requestId 指定的调用的指标。仅当调用包括冷启动时，`initDurationMs` 字段才会包含在日志中。如果 AWS X-Ray 跟踪处于活动状态，日志会包含 X-Ray 元数据。以下示例显示了包括冷启动的调用的平台报告日志。

```
{     
    "time": "2020-08-20T12:31:32.123Z",
    "type": "platform.report",
    "record": {"requestId": "6f7f0961f83442118a7af6fe80b88d56",
        "metrics": {"durationMs": 101.51,
            "billedDurationMs": 300,
            "memorySizeMB": 512,
            "maxMemoryUsedMB": 33,
            "initDurationMs": 116.67
        }
    }
}
```

平台故障日志捕获运行时或执行环境错误。以下示例显示了平台故障日志消息。

```
{     
    "time": "2020-08-20T12:31:32.123Z",
    "type": "platform.fault",
    "record": "RequestId: d783b35e-a91d-4251-af17-035953428a2c Process exited before completing request"
}
```

**注意**  
AWS 目前正在实施对 Lambda 服务的更改。由于这些更改，您可能会看到 AWS 账户 中不同 Lambda 函数发出的系统日志消息和跟踪分段的结构和内容之间存在细微差异。  
受此更改影响的日志输出之一是平台故障日志 `"record"` 字段。以下示例显示了新旧格式的说明性 `"record"` 字段。新样式的故障日志包含更简洁的消息  
这些更改将在未来几周内实施，除中国和 GovCloud 区域外，所有 AWS 区域 的函数都将过渡到使用新格式的日志消息和跟踪分段。



**Example 平台故障日志记录（旧样式）**  

```
"record":"RequestId: ...\tError: Runtime exited with error: exit status 255\nRuntime.ExitError"
```

**Example 平台故障日志记录（新样式）**  

```
"record":"RequestId: ... Status: error\tErrorType: Runtime.ExitError"
```

在扩展利用扩展 API 注册时，Lambda 会生成平台扩展日志。以下示例显示了平台扩展消息。

```
{     
    "time": "2020-08-20T12:31:32.123Z",
    "type": "platform.extension",
    "record": {"name": "Foo.bar",
        "state": "Ready",
        "events": ["INVOKE", "SHUTDOWN"]
     }
}
```

在扩展订阅日志 API 时，Lambda 会生成平台日志订阅日志。以下示例显示了日志订阅消息。

```
{     
    "time": "2020-08-20T12:31:32.123Z",
    "type": "platform.logsSubscription",
    "record": {"name": "Foo.bar",
        "state": "Subscribed",
        "types": ["function", "platform"],
    }
}
```

当扩展无法处理其接收的日志数量时，Lambda 会生成平台日志丢弃日志。以下示例显示了 `platform.logsDropped` 日志消息。

```
{     
    "time": "2020-08-20T12:31:32.123Z",
    "type": "platform.logsDropped",
    "record": {"reason": "Consumer seems to have fallen behind as it has not acknowledged receipt of logs.",
        "droppedRecords": 123,
        "droppedBytes" 12345
    }
}
```

**platform.restoreStart** 日志消息显示 `Restore` 阶段的开始时间（仅限 `snap-start` 初始化类型）。示例：

```
{ 
  "time":"2022-07-17T18:43:44.782Z", 
  "type":"platform.restoreStart", 
  "record":{} 
}
```

**platform.restoreReport** 日志消息显示 `Restore` 阶段的持续时间以及该阶段已计费的毫秒数（仅限 `snap-start` 初始化类型）。示例：

```
{
  "time":"2022-07-17T18:43:45.936Z",
  "type":"platform.restoreReport",
  "record":{
      "metrics":{
          "durationMs":70.87,
          "billedDurationMs":13
      }
  }
}
```

#### 平台 `runtimeDone` 消息
<a name="runtimes-logs-api-ref-done"></a>

如果在订阅请求中将架构版本设置为“2021-03-18”，则在函数调用成功完成或出现错误后，Lambda 会发送一条 `platform.runtimeDone` 消息。扩展可以使用此消息来停止此函数调用的所有遥测收集。

架构版本 ** 2021-03-18 ** 中日志事件类型的 OpenAPI 规范可从此处获得：[schema-2021-03-18.zip](samples/schema-2021-03-18.zip)

在运行时发送 `Next` 或 `Error` 运行时 API 请求时，Lambda 会生成 `platform.runtimeDone` 日志消息。`platform.runtimeDone` 日志会通知 Logs API 的使用者函数调用已完成。扩展可以使用此信息来决定何时发送在调用期间收集的所有遥测数据。

##### 示例
<a name="runtimes-logs-api-examples"></a>

在函数调用完成时，Lambda 会在运行时发送 NEXT 请求后发送 `platform.runtimeDone` 消息。以下示例显示了每个状态值的消息：成功、失败和超时。

**Example 成功消息示例**  

```
{
    "time": "2021-02-04T20:00:05.123Z",
    "type": "platform.runtimeDone",
    "record": {
       "requestId":"6f7f0961f83442118a7af6fe80b88",
       "status": "success"
    }
}
```

**Example 失败消息示例**  

```
{
   "time": "2021-02-04T20:00:05.123Z",
   "type": "platform.runtimeDone",
   "record": {
      "requestId":"6f7f0961f83442118a7af6fe80b88",
      "status": "failure"
   }
}
```

**Example 超时消息示例**  

```
{
   "time": "2021-02-04T20:00:05.123Z",
   "type": "platform.runtimeDone",
   "record": {
      "requestId":"6f7f0961f83442118a7af6fe80b88",
      "status": "timeout"
  }
}
```

**Example platform.restoreRuntimeDone 消息示例（仅限 `snap-start` 初始化类型）**  
**platform.restoreRuntimeDone** 日志消息显示 `Restore` 阶段是否成功。当运行时发送 `restore/next` 运行时 API 请求时，Lambda 会发送此消息。存在三种可能的状态：成功、失败和超时。以下示例显示了成功的 **platform.restoreRuntimeDone** 日志消息。  

```
{
  "time":"2022-07-17T18:43:45.936Z",
  "type":"platform.restoreRuntimeDone",
  "record":{
      "status":"success"
  }
}
```