

# 使用 Python 构建 Lambda 函数
<a name="lambda-python"></a>

您可以在 AWS Lambda 中运行 Python。Lambda 为 Python 提供[运行时](lambda-runtimes.md)运行您的代码来处理事件。您的代码在包含 SDK for Python (Boto3) 的环境中运行，其中包含来自您管理的 AWS Identity and Access Management (IAM) 角色的凭证。要了解有关 Python 运行时随附的 SDK 版本的更多信息，请参阅 [包含运行时的 SDK 版本](#python-sdk-included)。

Lambda 支持以下 Python 运行时。


| 名称 | 标识符 | 操作系统 | 弃用日期 | 阻止函数创建 | 阻止函数更新 | 
| --- | --- | --- | --- | --- | --- | 
|  Python 3.14  |  `python3.14`  |  Amazon Linux 2023  |   2029 年 6 月 30 日   |   2029 年 7 月 31 日   |   2029 年 8 月 31 日   | 
|  Python 3.13  |  `python3.13`  |  Amazon Linux 2023  |   2029 年 6 月 30 日   |   2029 年 7 月 31 日   |   2029 年 8 月 31 日   | 
|  Python 3.12  |  `python3.12`  |  Amazon Linux 2023  |   2028 年 10 月 31 日   |   2028 年 11 月 30 日   |   2029 年 1 月 10 日   | 
|  Python 3.11  |  `python3.11`  |  Amazon Linux 2  |   2027 年 6 月 30 日   |   2027 年 7 月 31 日   |   2027 年 8 月 31 日   | 
|  Python 3.10  |  `python3.10`  |  Amazon Linux 2  |   2026 年 10 月 31 日   |   2026 年 11 月 30 日   |   2027 年 1 月 15 日   | 

**创建 Python 函数**

1. 打开 [Lambda 控制台](https://console.aws.amazon.com/lambda)。

1. 选择 **Create function**（创建函数）。

1. 配置以下设置：
   + **函数名称**：输入函数名称。
   + **运行时系统**：选择 **Python 3.14**。

1. 选择**创建函数**。

控制台将使用名为 `lambda_function` 的源文件创建一个 Lambda 函数。您可以在内置代码编辑器中编辑此文件并添加更多文件。在**部署**部分，选择**部署**以更新函数的代码。然后，要运行您的代码，请在**测试事件**部分中选择**创建测试事件**。

您的 Lambda 函数附带了 CloudWatch Logs 日志组。函数运行时会将每次调用的详细信息发送到 CloudWatch Logs。该运行时会中继调用期间[函数输出的任何日志](python-logging.md)。如果您的函数返回错误，则 Lambda 将为错误设置格式，并将其返回给调用方。

**Topics**
+ [包含运行时的 SDK 版本](#python-sdk-included)
+ [已禁用的 Python 特征](#python-disabled-features)
+ [响应格式](#python-response-format)
+ [顺利关闭扩展程序](#python-graceful-shutdown)
+ [定义采用 Python 的 Lambda 函数处理程序](python-handler.md)
+ [将 .zip 文件归档用于 Python Lambda 函数](python-package.md)
+ [使用容器镜像部署 Python Lambda 函数](python-image.md)
+ [使用 Python Lambda 函数的层](python-layers.md)
+ [使用 Lambda 上下文对象检索 Python 函数信息](python-context.md)
+ [Python Lambda 函数日志记录和监控](python-logging.md)
+ [Python 中的 AWS Lambda 函数测试](python-testing.md)
+ [在 AWS Lambda 中检测 Python 代码](python-tracing.md)

## 包含运行时的 SDK 版本
<a name="python-sdk-included"></a>

Python 运行时中包含的 AWS SDK 版本取决于运行时版本和您的 AWS 区域。要查找您正在使用的运行时中包含的 SDK 的版本，请使用以下代码创建 Lambda 函数。

```
import boto3
import botocore

def lambda_handler(event, context):
   print(f'boto3 version: {boto3.__version__}')
   print(f'botocore version: {botocore.__version__}')
```

## 已禁用的 Python 特征
<a name="python-disabled-features"></a>

下表列出了在 Lambda 托管运行时和 Python 容器基础映像中禁用的 Python 特征。这些特征必须在编译 Python 运行时可执行文件时启用，不能通过使用执行时间标志来启用。要在 Lambda 中使用这些特征，您可以使用[容器映像](python-image.md#python-image-clients)或[自定义运行时](runtimes-custom.md)，在启用这些特征的情况下部署自己的 Python 运行时版本。


| Python 特征 | 受影响的 Python 版本 | Status | 
| --- | --- | --- | 
| 即时（JIT）编译器 | Python 3.13 及更高版本 | JIT 编译器是实验性的，不建议用于生产工作负载。因此，它在 Lambda Python 运行时中被禁用。 | 
| 自由线程 | Python 3.13 及更高版本 | 由于对单线程代码的性能影响，Lambda Python 版本中禁用了自由线程（禁用全局解释器锁的选项）。 | 

## 响应格式
<a name="python-response-format"></a>

在 Python 3.12 及更高版本的 Python 运行时系统中，函数作为其 JSON 响应的一部分返回 Unicode 字符。早期的 Python 运行时系统在响应中返回 Unicode 字符的转义序列。例如，在 Python 3.11 中，如果您返回诸如“こんにちは”之类的 Unicode 字符串，它会转义 Unicode 字符并返回“\$1u3053\$1u3093\$1u306b\$1u3061\$1u306f”。Python 3.12 运行时系统会返回原始的“こんにちは”。

使用 Unicode 响应可以减小 Lambda 响应的大小，从而更轻松地将较大的响应容纳到同步函数 6 MB 的最大有效载荷大小中。在前面的示例中，转义后的版本为 32 个字节，而 Unicode 字符串的转义版本为 17 个字节。

升级到 Python 3.12 或更高版本 Python 运行时后，可能需要调整代码以适应新的响应格式。如果调用方期望使用转义 Unicode，则必须在返回函数中添加代码以手动转义 Unicode，或者调整调用方以处理 Unicode 返回。

## 顺利关闭扩展程序
<a name="python-graceful-shutdown"></a>

Python 3.12 及更高版本的 Python 运行时系统为带有[外部扩展程序](lambda-extensions.md)的函数提供了改进的顺利关闭功能。当 Lambda 关闭执行环境时，它会向运行时系统发送 `SIGTERM` 信号，然后将一个 `SHUTDOWN` 事件发送给每个注册的外部扩展。您可以在 Lambda 函数中捕获 `SIGTERM` 信号，并清理该函数创建的资源，例如数据库连接。

要了解有关执行环境生命周期的更多信息，请参阅 [了解 Lambda 执行环境生命周期](lambda-runtime-environment.md)。有关如何顺利关闭扩展程序的示例，请参阅 [AWS Samples GitHub Repository](https://github.com/aws-samples/graceful-shutdown-with-aws-lambda)。

# 定义采用 Python 的 Lambda 函数处理程序
<a name="python-handler"></a>

Lambda 函数*处理程序*是函数代码中处理事件的方法。当调用函数时，Lambda 运行处理程序方法。您的函数会一直运行，直到处理程序返回响应、退出或超时。

本页介绍如何使用采用 Python 的 Lambda 函数处理程序，包括命名约定、有效的处理程序签名和代码最佳实践。本页还包括 Python Lambda 函数的示例，该函数接收订单信息，生成文本文件收据，然后将此文件放入 Amazon Simple Storage Service（Amazon S3）存储桶中。

**Topics**
+ [示例 Python Lambda 函数代码](#python-handler-example)
+ [处理程序命名约定](#python-handler-naming)
+ [使用 Lambda 事件对象](#python-handler-event)
+ [访问和使用 Lambda 上下文对象](#python-handler-context)
+ [Python 处理程序的有效处理程序签名](#python-handler-signature)
+ [返回值](#python-handler-return)
+ [在处理程序中使用 适用于 Python (Boto3) 的 AWS SDK](#python-handler-sdk)
+ [评估环境变量](#python-handler-env-vars)
+ [Python Lambda 函数的代码最佳实践](#python-handler-best-practices)

## 示例 Python Lambda 函数代码
<a name="python-handler-example"></a>

以下示例 Python Lambda 函数代码接收有关订单的信息，生成文本文件接收，并将此文件放入 Amazon S3 存储桶中：

**Example Python Lambda 函数**  

```
import json
import os
import logging
import boto3

# Initialize the S3 client outside of the handler
s3_client = boto3.client('s3')

# Initialize the logger
logger = logging.getLogger()
logger.setLevel("INFO")

def upload_receipt_to_s3(bucket_name, key, receipt_content):
    """Helper function to upload receipt to S3"""
    
    try:
        s3_client.put_object(
            Bucket=bucket_name,
            Key=key,
            Body=receipt_content
        )
    except Exception as e:
        logger.error(f"Failed to upload receipt to S3: {str(e)}")
        raise

def lambda_handler(event, context):
    """
    Main Lambda handler function
    Parameters:
        event: Dict containing the Lambda function event data
        context: Lambda runtime context
    Returns:
        Dict containing status message
    """
    try:
        # Parse the input event
        order_id = event['Order_id']
        amount = event['Amount']
        item = event['Item']
        
        # Access environment variables
        bucket_name = os.environ.get('RECEIPT_BUCKET')
        if not bucket_name:
            raise ValueError("Missing required environment variable RECEIPT_BUCKET")

        # Create the receipt content and key destination
        receipt_content = (
            f"OrderID: {order_id}\n"
            f"Amount: ${amount}\n"
            f"Item: {item}"
        )
        key = f"receipts/{order_id}.txt"

        # Upload the receipt to S3
        upload_receipt_to_s3(bucket_name, key, receipt_content)

        logger.info(f"Successfully processed order {order_id} and stored receipt in S3 bucket {bucket_name}")
        
        return {
            "statusCode": 200,
            "message": "Receipt processed successfully"
        }

    except Exception as e:
        logger.error(f"Error processing order: {str(e)}")
        raise
```

此 文件包含以下代码部分：
+ `import` 数据块：使用此数据块来包含 Lambda 函数所需的库。
+ SDK 客户端和记录程序的全局初始化：在处理程序之外包括初始化代码可利用[执行环境](lambda-runtime-environment.md)重用来提高函数性能。请参阅[Python Lambda 函数的代码最佳实践](#python-handler-best-practices)，了解更多信息。
+ `def upload_receipt_to_s3(bucket_name, key, receipt_content):` 这是一个由主 `lambda_handler` 函数调用的辅助函数。
+ `def lambda_handler(event, context):`：这是您的代码的**主处理程序函数**，包含主应用程序逻辑。当 Lambda 调用您的函数处理程序时，[Lambda 运行时](concepts-basics.md#gettingstarted-concepts-runtime)会向该函数传递两个参数，一个是包含要处理的函数的数据的[事件对象](#python-handler-event)，另一个是包含函数调用相关信息的[上下文对象](#python-handler-context)。

## 处理程序命名约定
<a name="python-handler-naming"></a>

在创建 Lambda 函数时定义的函数处理程序名称来自以下内容：
+ Lambda 处理程序函数所在的文件名称。
+ Python 处理程序函数的名称。

在上面的示例中，如果文件名为 `lambda_function.py`，则处理程序将被指定为 `lambda_function.lambda_handler`。这是为您使用 Lambda 控制台创建的函数所指定的默认处理程序名称。

如果您在控制台中使用不同的文件名或函数处理程序名称创建函数，则必须编辑默认处理程序名称。

**更改函数处理程序名称（控制台）**

1. 打开 Lambda 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面，然后选择一个函数。

1. 选择**节点**选项卡。

1. 向下滚动到**运行时设置**窗格并选择**编辑**。

1. 在**处理程序**中，输入函数处理程序的新名称。

1. 选择**保存**。

## 使用 Lambda 事件对象
<a name="python-handler-event"></a>

当 Lambda 调用函数时，它会将[事件对象](concepts-basics.md#gettingstarted-concepts-event)参数传递给函数处理程序。JSON 对象是 Lambda 函数的最常用事件格式。在上一部分的代码示例中，该函数需要以下格式的输入：

```
{
    "Order_id": "12345",
    "Amount": 199.99,
    "Item": "Wireless Headphones"
}
```

如果您的函数被其他 AWS 服务调用，则输入事件也是 JSON 对象。事件对象的确切格式由调用函数的服务决定。要查看特定服务的事件格式，请参阅 [使用来自其 AWS 他服务的事件调用 Lambda](lambda-services.md) 章节中的相应页面。

如果输入事件采用 JSON 对象的形式，则 Lambda 运行时将该对象转换为 Python 字典。要将输入 JSON 中的值分配给代码中的变量，请使用标准的 Python 字典方法，如示例代码所示。

您也可以将数据作为 JSON 数组或任何其他有效的 JSON 数据类型传递给函数。下表就 Python 运行时如何转换这些 JSON 类型进行了定义。


| JSON 数据类型 | Python 数据类型 | 
| --- | --- | 
| object | 字典（dict） | 
| 数组 | 列表（list） | 
| 数字 | 整数（int）或浮点数（float） | 
| 字符串 | 字符串（str） | 
| 布尔值 | 布尔值（bool） | 
| null | NoneType（NoneType） | 

## 访问和使用 Lambda 上下文对象
<a name="python-handler-context"></a>

Lambda 上下文对象包含有关函数调用和执行环境的信息。Lambda 会在被调用时自动将上下文对象传递给函数。您可以使用上下文对象输出有关函数调用的信息，以便进行监控。

上下文对象是在 [Lambda 运行时接口客户端](https://github.com/aws/aws-lambda-python-runtime-interface-client/blob/main/awslambdaric/lambda_context.py)中定义的 Python 类。要返回任何上下文对象属性的值，请对上下文对象使用相应的方法。例如，以下代码段将 `aws_request_id` 属性的值（调用请求的标识符）分配给名为 `request` 的变量。

```
request = context.aws_request_id
```

要了解有关使用 Lambda 上下文对象的更多信息并查看可用方法和属性的完整列表，请参阅 [使用 Lambda 上下文对象检索 Python 函数信息](python-context.md)。

## Python 处理程序的有效处理程序签名
<a name="python-handler-signature"></a>

在 Python 中定义处理程序函数时，该函数必须采用两个参数。这些参数中的第一个是 Lambda [事件对象](#python-handler-event)，第二个是 Lambda [上下文对象](#python-handler-context)。按照惯例，这些输入参数通常命名为 `event` 和 `context`，但您可以给它们指定任何您想要的姓名。如果您使用单个输入参数声明处理程序函数，则 Lambda 在尝试运行您的函数时将引发错误。在 Python 中声明处理程序函数的最常用方法如下：

```
def lambda_handler(event, context):
```

您也可以在函数声明中使用 Python 类型提示，如以下示例所示：

```
from typing import Dict, Any
      
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
```

要对其他 AWS 服务生成的事件和上下文对象使用特定的 AWS 类型，请将 `aws-lambda-typing` 程序包添加到函数的部署包中。您可以通过运行 `pip install aws-lambda-typing` 将此库安装到您的开发环境中。以下代码段演示如何使用特定于 AWS 的类型提示。在此示例中，预期事件是 Amazon S3 事件。

```
from aws_lambda_typing.events import S3Event
from aws_lambda_typing.context import Context
from typing import Dict, Any

def lambda_handler(event: S3Event, context: Context) -> Dict[str, Any]:
```

不能将 Python `async` 函数类型用于处理程序函数。

## 返回值
<a name="python-handler-return"></a>

（可选）处理程序可返回值，该值必须是 JSON 可序列化的。常见的返回类型包括 `dict`、`list`、`str`、`int`、`float` 和 `bool`。

返回值所发生的状态取决于调用函数的[调用类型](lambda-invocation.md)和[服务](lambda-services.md)。例如：
+ 如果您使用 `RequestResponse` 调用类型[同步调用 Lambda 函数](invocation-sync.md)，Lambda 会将 Python 函数调用的结果返回到调用 Lambda 函数的客户端（在对调用请求的 HTTP 响应中，序列化为 JSON）。例如，AWS Lambda 控制台使用 `RequestResponse` 调用类型，因此当您使用控制台调用函数时，控制台将显示返回的值。
+ 如果处理程序返回 `json.dumps` 无法序列化的对象，则运行时返回错误。
+ 如果处理程序返回 `None`（就像不具有 `return` 语句的 Python 函数隐式执行的那样），则运行时返回 `null`。
+ 如果您使用 `Event` 调用类型（一种[异步调用](invocation-async.md)），则该值将被丢弃。

在示例代码中，处理程序返回以下 Python 字典：

```
{
  "statusCode": 200,
  "message": "Receipt processed successfully"
}
```

Lambda 运行时会序列化此字典，并将其作为 JSON 字符串返回到调用该函数的客户端。

**注意**  
在 Python 3.9 及更高版本中，Lambda 在错误响应中包含调用的 requestId。

## 在处理程序中使用 适用于 Python (Boto3) 的 AWS SDK
<a name="python-handler-sdk"></a>

通常，您将使用 Lambda 函数与其他 AWS 服务 和资源进行交互。与此类资源最简单的交互方法是使用 适用于 Python (Boto3) 的 AWS SDK。所有[支持的 Lambda Python 运行时](lambda-runtimes.md#runtimes-supported)都包含适用于 Python 的 SDK 的一个版本。但是，如果您的代码需要使用 SDK，强烈建议您将其包含在函数的部署包中。在部署包中包含 SDK 可以让您完全控制依赖项，并降低与其他库发生版本不一致问题的风险。要了解更多信息，请参阅 [Python 中的运行时系统依赖项](python-package.md#python-package-dependencies) 和 [向后兼容性](runtimes-update.md#runtime-update-compatibility)。

要在 Lambda 函数中使用适用于 Python 的 SDK，请在函数代码开头的导入块中添加以下语句：

```
import boto3
```

使用 `pip install` 命令将 `boto3` 库添加到函数的部署包中。有关如何向 .zip 部署包添加依赖项的详细说明，请参阅 [创建含依赖项的 .zip 部署包](python-package.md#python-package-create-dependencies)。要详细了解如何向部署为容器映像的 Lambda 函数添加依赖项，请参阅 [从基本映像创建映像](python-image.md#python-image-create) 或 [从备用基本映像创建映像](python-image.md#python-alt-create)。

在代码中使用 `boto3` 时，无需提供任何凭证即可初始化客户端。例如，在示例代码中，我们使用以下代码行初始化 Amazon S3 客户端：

```
# Initialize the S3 client outside of the handler
s3_client = boto3.client('s3')
```

使用 Python，Lambda 会自动创建带有凭证的环境变量。`boto3` SDK 会在初始化期间检查函数的环境变量中是否存在这些凭证。

## 评估环境变量
<a name="python-handler-env-vars"></a>

在处理程序代码中，您可以使用 `os.environ.get` 方法引用[环境变量](configuration-envvars.md)。在示例代码中，我们使用以下代码行引用已定义的 `RECEIPT_BUCKET` 环境变量：

```
# Access environment variables
bucket_name = os.environ.get('RECEIPT_BUCKET')
```

请勿遗忘在代码开头的导入块中包含一条 `import os` 语句。

## Python Lambda 函数的代码最佳实践
<a name="python-handler-best-practices"></a>

在构建 Lambda 函数时，请遵循以下列表中的指南，采用最佳编码实践：
+ **从核心逻辑中分离 Lambda 处理程序。**这样您可以创建更容易进行单元测试的函数。例如，在 Python 中，如下所示：

  ```
  def lambda_handler(event, context):
      foo = event['foo']
      bar = event['bar']      
      result = my_lambda_function(foo, bar)
  
  def my_lambda_function(foo, bar):
      // MyLambdaFunction logic here
  ```
+ **控制函数部署包中的依赖项。**AWS Lambda 执行环境包含许多库。对于 Node.js 和 Python 运行时，其中包括 AWS SDK。Lambda 会定期更新这些库，以支持最新的功能组合和安全更新。这些更新可能会使 Lambda 函数的行为发生细微变化。要完全控制您的函数所用的依赖项，请使用部署程序包来打包所有依赖项。
+ **将依赖关系的复杂性降至最低。**首选在[执行环境](lambda-runtime-environment.md)启动时可以快速加载的更简单的框架。
+ **将部署包大小精简为只包含运行时必要的部分。**这样会减少调用前下载和解压缩部署程序包所需的时间。

**利用执行环境重用来提高函数性能。**连接软件开发工具包 (SDK) 客户端和函数处理程序之外的数据库，并在 `/tmp` 目录中本地缓存静态资产。由函数的同一实例处理的后续调用可重用这些资源。这样就可以通过缩短函数运行时间来节省成本。

为了避免调用之间潜在的数据泄露，请不要使用执行环境来存储用户数据、事件或其他具有安全影响的信息。如果您的函数依赖于无法存储在处理程序的内存中的可变状态，请考虑为每个用户创建单独的函数或单独的函数版本。

**使用 keep-alive 指令来维护持久连接。**Lambda 会随着时间的推移清除空闲连接。在调用函数时尝试重用空闲连接会导致连接错误。要维护您的持久连接，请使用与运行时关联的 keep-alive 指令。有关示例，请参阅[在 Node.js 中通过 Keep-Alive 重用连接](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html)。

**使用[环境变量](configuration-envvars.md)将操作参数传递给函数。**例如，您在写入 Amazon S3 存储桶时，不应对要写入的存储桶名称进行硬编码，而应将存储桶名称配置为环境变量。

**避免在 Lambda 函数中使用递归调用**，在这种情况下，函数会调用自己或启动可能再次调用该函数的进程。这可能会导致意想不到的函数调用量和升级成本。如果您看到意外的调用量，请立即将函数保留并发设置为 `0` 来限制对函数的所有调用，同时更新代码。

Lambda 函数代码中**不要使用非正式的非公有 API**。对于 AWS Lambda 托管式运行时，Lambda 会定期为 Lambda 的内部 API 应用安全性和功能更新。这些内部 API 更新可能不能向后兼容，会导致意外后果，例如，假设您的函数依赖于这些非公有 API，则调用会失败。请参阅 [API 参考](https://docs.aws.amazon.com/lambda/latest/api/welcome.html)以查看公开发布的 API 列表。

**编写幂等代码。**为您的函数编写幂等代码可确保以相同的方式处理重复事件。您的代码应该正确验证事件并优雅地处理重复事件。有关更多信息，请参阅[如何使我的 Lambda 函数具有幂等性？](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/)。

# 将 .zip 文件归档用于 Python Lambda 函数
<a name="python-package"></a>

 AWS Lambda 函数的代码包含一个 .py 文件，其中包含函数的处理程序代码，以及代码所依赖的任何其他包和模块。要将此函数部署到 Lambda，您可以使用*部署包*。此包可以是 .zip 文件归档或容器映像。有关在 Python 中使用容器映像的更多信息，请参阅使用[容器映像部署 Python Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/python-image.html)。

 要创建 .zip 文件归档格式的部署包，可以使用命令行工具内置的 .zip 文件归档实用工具或任何其他 .zip 文件实用工具（例如 [7zip](https://www.7-zip.org/download.html)）。以下各部分中显示的示例假设您在 Linux 或 macOS 环境中使用命令行 `zip` 工具。要在 Windows 中使用相同命令，您可以安装 [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10)，以获取 Windows 集成版本的 Ubuntu 和 Bash。

 请注意，Lambda 使用 POSIX 文件权限，因此在创建 .zip 文件归档之前，您可能需要[为部署包文件夹设置权限](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-deployment-package-errors/)。

**Topics**
+ [Python 中的运行时系统依赖项](#python-package-dependencies)
+ [创建不含依赖项的 .zip 部署包](#python-package-create-no-dependencies)
+ [创建含依赖项的 .zip 部署包](#python-package-create-dependencies)
+ [依赖项搜索路径和包含运行时系统的库](#python-package-searchpath)
+ [使用 \$1\$1pycache\$1\$1 文件夹](#python-package-pycache)
+ [使用原生库创建 .zip 部署包](#python-package-native-libraries)
+ [使用 .zip 文件创建和更新 Python Lambda 函数](#python-package-create-update)

## Python 中的运行时系统依赖项
<a name="python-package-dependencies"></a>

对于使用 Python 运行时系统的 Lambda 函数，依赖项可以是任何 Python 程序包或模块。使用 .zip 存档部署函数时，可以使用函数代码或使用 [Lambda 层](chapter-layers.md)将这些依赖项添加到 .zip 文件中。层是可以包含其他代码或其他内容的单独的 .zip 文件。要了解在 Python 中使用 Lambda 层的更多信息，请参阅[使用 Python Lambda 函数的层](python-layers.md)。

Lambda Python 运行时系统包含 适用于 Python (Boto3) 的 AWS SDK 及其依赖项。Lambda 会在运行时系统中为您无法添加自定义依赖项的部署场景提供开发工具包。这些场景包括使用内置代码编辑器在控制台中创建函数，或者使用 AWS Serverless Application Model（AWS SAM）或 CloudFormation 模板中的内联函数。

Lambda 会定期更新 Python 运行时系统中的库，以包含最新更新和安全补丁。如果函数使用运行时系统中包含的 Boto3 SDK 版本，但部署包包含开发工具包依赖项，可能会导致版本不一致问题。例如，部署包可能包含开发工具包依赖项 urllib3。当 Lambda 在运行时系统中更新开发工具包时，运行时系统的新版本与部署包中的 urllib3 版本之间的兼容性问题可能会导致您的函数失败。

**重要**  
为了保持对依赖项的完全控制并避免可能的版本不一致问题，我们建议您将所有函数的依赖项添加到部署包中，即使它们的版本已包含在 Lambda 运行时系统中也是如此。这包括 Boto3 SDK。

要查找正在使用的运行时系统中包含哪个版本的 SDK for Python（Boto3），请参阅 [包含运行时的 SDK 版本](lambda-python.md#python-sdk-included)。

 在 [AWS 责任共担模式](https://docs.aws.amazon.com/whitepapers/latest/aws-risk-and-compliance/shared-responsibility-model.html)下，您负责管理函数部署包中的所有依赖项。这包括应用更新和安全补丁。要更新函数部署包中的依赖项，请先创建一个新的 .zip 文件，然后将其上传到 Lambda 中。有关更多信息，请参阅 [创建含依赖项的 .zip 部署包](#python-package-create-dependencies) 和 [使用 .zip 文件创建和更新 Python Lambda 函数](#python-package-create-update)。

## 创建不含依赖项的 .zip 部署包
<a name="python-package-create-no-dependencies"></a>

 如果您的函数代码没有依赖项，则 .zip 文件仅包含带有函数处理程序代码的 .py 文件。使用您的首选 zip 实用工具创建一个 .zip 文件，并将 .py 文件置于根目录中。如果 .py 文件不在 .zip 文件的根目录下，Lambda 将无法运行代码。

 要了解如何部署 .zip 文件以创建新的 Lambda 函数或更新现有函数，请参阅 [使用 .zip 文件创建和更新 Python Lambda 函数](#python-package-create-update)。

## 创建含依赖项的 .zip 部署包
<a name="python-package-create-dependencies"></a>

 如果函数代码依赖其他包或模块，可以使用函数代码或[使用 Lambda 层](python-layers.md)将这些依赖项添加到 .zip 文件中。本部分中的说明向您展示了如何将依赖项包含在 .zip 部署包中。要让 Lambda 运行代码，必须将包含处理程序代码和所有函数依赖项的.py 文件安装在.zip 文件的根目录下。

 假设函数代码保存在名为 `lambda_function.py` 的文件中。以下示例 CLI 命令将创建名为 `my_deployment_package.zip` 的 .zip 文件，其中包含函数代码及其依赖项。您可以将依赖项直接安装到项目目录中的文件夹，也可以使用 Python 虚拟环境。

**要创建部署包（项目目录）**

1. 导航到包含 `lambda_function.py` 源代码文件的项目目录。在此示例中，该目录名为 `my_function`。

   ```
   cd my_function
   ```

1. 创建将在其中安装依赖项的名为 package 的新目录。

   ```
   mkdir package
   ```

   请注意，对于 .zip 部署包，Lambda 期望源代码及其依赖项全部位于 .zip 文件的根目录中。但是，直接在项目目录中安装依赖项可能会引入大量新文件和文件夹，使在 IDE 中导航变得困难。您可以在此目录中创建一个单独的 `package` 目录，以将依赖项与源代码分开。

1. 在 `package` 目录中安装依赖项。以下示例将使用 pip 从 Python 程序包索引中安装 Boto3 SDK。如果函数代码使用您自己创建的 Python 程序包，请将这类程序包保存在 `package` 目录中。

   ```
   pip install --target ./package boto3
   ```

1. 创建包含已安装库在根目录中的 .zip 文件。

   ```
   cd package
   zip -r ../my_deployment_package.zip .
   ```

   这样会在您的项目目录中生成一个 `my_deployment_package.zip` 文件。

1. 将 lambda\$1function.py 文件添加到 .zip 文件的根目录中。

   ```
   cd ..
   zip my_deployment_package.zip lambda_function.py
   ```

   .zip 文件应采用扁平目录结构，将函数的处理程序代码和所有依赖项文件夹安装在根目录中，如下所示。

   ```
   my_deployment_package.zip
   |- bin
   |  |-jp.py
   |- boto3
   |  |-compat.py
   |  |-data
   |  |-docs
   ...
   |- lambda_function.py
   ```

   如果包含函数的处理程序代码的 .py 文件不在 .zip 文件的根目录中，Lambda 将无法运行代码。

**要创建部署包（虚拟环境）**

1. 在项目目录中创建和激活虚拟环境。在此示例中，项目目录名为 `my_function`。

   ```
   ~$ cd my_function
   ~/my_function$ python3.14 -m venv my_virtual_env
   ~/my_function$ source ./my_virtual_env/bin/activate
   ```

1. 使用 pip 安装所需的库。下面的示例将安装 Boto3 SDK

   ```
   (my_virtual_env) ~/my_function$ pip install boto3
   ```

1. 使用 `pip show` 在虚拟环境中查找 pip 安装依赖项的位置。

   ```
   (my_virtual_env) ~/my_function$ pip show <package_name>
   ```

   pip 在其中安装库的文件夹可能名为 `site-packages` 或 `dist-packages`。此文件夹可能位于 `lib/python3.x` 或 `lib64/python3.x` 目录中（其中 python3.x 代表正在使用的 Python 版本）。

1. 停用虚拟环境

   ```
   (my_virtual_env) ~/my_function$ deactivate
   ```

1. 导航到包含使用 pip 安装了依赖项的目录，并在项目目录中创建一个 .zip 文件，将已安装的依赖项置于其根目录。在此示例中，pip 已在 `my_virtual_env/lib/python3.14/site-packages` 目录中安装了所需依赖项。

   ```
   ~/my_function$ cd my_virtual_env/lib/python3.14/site-packages
   ~/my_function/my_virtual_env/lib/python3.14/site-packages$ zip -r ../../../../my_deployment_package.zip .
   ```

1. 导航到包含处理程序代码的 .py 文件所在的项目目录的根目录，然后将该文件添加到 .zip 程序包的根目录中。在此示例中，您的函数代码文件名为 `lambda_function.py`。

   ```
   ~/my_function/my_virtual_env/lib/python3.14/site-packages$ cd ../../../../
   ~/my_function$ zip my_deployment_package.zip lambda_function.py
   ```

## 依赖项搜索路径和包含运行时系统的库
<a name="python-package-searchpath"></a>

 在代码中使用 `import` 语句时，Python 运行时系统会搜索其搜索路径中的目录，直到找到相应模块或包。默认情况下，运行时系统搜索的第一个位置是解压缩并安装 .zip 部署包的目录 (`/var/task`)。如果部署包含有包含运行时系统的库的某个版本，则此版本将优先于运行时系统中包含的版本。部署包中的依赖项也优先于层中的依赖项。

 当您向层添加依赖项时，Lambda 会将其提取到 `/opt/python/lib/python3.x/site-packages`（其中 `python3.x` 表示正在使用的运行时系统版本）或 `/opt/python` 中。在搜索路径中，这些目录优先于含有包含运行时系统的库和安装了 pip 的库的目录（`/var/runtime` 和 `/var/lang/lib/python3.x/site-packages`）。因此，函数层中的库优先于运行时系统中包含的版本。

**注意**  
在 Python 3.11 托管式运行时系统和基本映像中，AWS SDK 及其依赖项安装在 `/var/lang/lib/python3.11/site-packages` 目录中。

 通过添加以下代码段，您可以查看 Lambda 函数的完整搜索路径。

```
import sys
      
search_path = sys.path
print(search_path)
```

**注意**  
由于部署包或层中的依赖项优先于包含运行时系统的库，因此如果您在包中包含 urllib3 等开发工具包依赖项而不包含开发工具包，可能会导致版本不一致问题。如果您要部署自己的 Boto3 依赖项版本，则还必须将 Boto3 作为依赖项部署到部署包中。我们建议您打包函数的所有依赖项，即使运行时系统中包含各种版本也是如此。

 您还可以在 .zip 程序包内的单独文件夹中添加依赖项。例如，您可以将某个 Boto3 SDK 版本添加到 .zip 程序包中名为 `common` 的文件夹中。解压缩并安装 .zip 程序包后，此文件夹将放置在 `/var/task` 目录中。要在代码中使用 .zip 部署包中某个文件夹中的依赖项，请使用 `import from` 语句。例如，要使用 .zip 程序包中名为 `common` 的文件夹中的 Boto3 版本，请使用以下语句。

```
from common import boto3
```

## 使用 \$1\$1pycache\$1\$1 文件夹
<a name="python-package-pycache"></a>

 我们建议您不要在函数部署包中包含 `__pycache__` 文件夹。在具有不同架构或操作系统的生成计算机上编译的 Python 字节码可能与 Lambda 执行环境不兼容。

## 使用原生库创建 .zip 部署包
<a name="python-package-native-libraries"></a>

 如果您的函数仅使用纯 Python 程序包和模块，则可以使用 `pip install` 命令在任何本地生成计算机上安装依赖项并创建 .zip 文件。许多流行的 Python 库（包括 NumPy 和 Pandas）都不是纯 Python 的，包含用 C 或 C\$1\$1 编写的代码。将包含 C/C\$1\$1 代码的库添加到部署包时，必须正确构建包以确保它与 Lambda 执行环境兼容。

 Python 程序包索引（[PyPI](https://pypi.org/)）上提供的大多数包都以“wheel”（.whl 文件）的形式提供。.whl 文件是一种 zip 文件，它包含已构建的分发，其中包含针对特定操作系统和指令集架构的预编译二进制文件。要使部署包与 Lambda 兼容，您需要为 Linux 操作系统和函数的指令集架构安装轮子。

 有些包可能只能作为源分发提供。对于这些包，您需要自己编译和构建 C/C\$1\$1 组件。

 要查看哪些分发可用于所需的包，请执行以下操作：

1. 在 [Python 程序包索引主页](https://pypi.org/)上搜索程序包名称。

1. 选择要使用的包的版本。

1. 选择**下载文件**。

### 使用已构建分发（wheel）
<a name="python-package-wheels"></a>

 要下载与 Lambda 兼容的 wheel，请使用 pip `--platform` 选项。

 如果 Lambda 函数使用 **x86\$164** 指令集架构，请运行以下 `pip install` 命令以在 `package` 目录中安装兼容的 wheel。将 `--python 3.x` 替换为正在使用的 Python 运行时系统版本。

```
pip install \
--platform manylinux2014_x86_64 \
--target=package \
--implementation cp \
--python-version 3.x \
--only-binary=:all: --upgrade \
<package_name>
```

 如果函数使用的是 **arm64** 指令集架构，请运行以下命令。将 `--python 3.x` 替换为正在使用的 Python 运行时系统版本。

```
pip install \
--platform manylinux2014_aarch64 \
--target=package \
--implementation cp \
--python-version 3.x \
--only-binary=:all: --upgrade \
<package_name>
```

### 使用源分发
<a name="python-package-source-dist"></a>

 如果包仅作为源分发提供，则需要自己构建 C/C\$1\$1 库。要使包与 Lambda 执行环境兼容，您需要在使用相同 Amazon Linux 操作系统的环境中构建包。您可以通过在 Amazon Elastic Compute Cloud（Amazon EC2）Linux 实例中构建包来实现此目的。

 要了解如何启动并连接到 Amazon EC2 Linux 实例，请参阅**《Amazon EC2 用户指南》中的[开始使用 Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html)。

## 使用 .zip 文件创建和更新 Python Lambda 函数
<a name="python-package-create-update"></a>

 创建 .zip 部署包后，您可以用其创建新的 Lambda 函数或更新现有的 Lambda 函数。您可以使用 Lambda 控制台、AWS Command Line Interface 和 Lambda API 部署 .zip 程序包。您也可以使用 AWS Serverless Application Model（AWS SAM）和 CloudFormation 创建和更新 Lambda 函数。

Lambda 的 .zip 部署包的最大大小为 250MB（已解压缩）。请注意，此限制适用于您上传的所有文件（包括任何 Lambda 层）的组合大小。

Lambda 运行时需要权限才能读取部署包中的文件。在 Linux 权限八进制表示法中，Lambda 对于不可执行文件（rw-r--r--）需要 644 个权限，对于目录和可执行文件需要 755 个权限（rwxr-xr-x）。

在 Linux 和 MacOS 中，使用 `chmod` 命令更改部署包中文件和目录的文件权限。例如，要为不可执行文件提供正确的权限，请运行以下命令。

```
chmod 644 <filepath>
```

要在 Windows 中更改文件权限，请参阅 Microsoft Windows 文档中的 [Set, View, Change, or Remove Permissions on an Object](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc731667(v=ws.10))。

**注意**  
如果您不向 Lambda 授予访问部署包中目录所需的权限，Lambda 会将这些目录的权限设置为 755（rwxr-xr-x）。

### 使用控制台通过 .zip 文件创建和更新函数
<a name="python-package-create-console"></a>

 要创建新函数，必须先在控制台中创建该函数，然后上传您的 .zip 归档。要更新现有函数，请打开函数页面，然后按照相同的步骤添加更新的 .zip 文件。

 如果您的 .zip 文件小于 50MB，则可以通过直接从本地计算机上传该文件来创建或更新函数。对于大于 50MB 的 .zip 文件，必须首先将您的程序包上传到 Amazon S3 存储桶。有关如何使用 AWS 管理控制台 将文件上传到 Amazon S3 存储桶的说明，请参阅 [Amazon S3 入门](https://docs.aws.amazon.com/AmazonS3/latest/userguide/GetStartedWithS3.html)。要使用 AWS CLI 上传文件，请参阅《AWS CLI 用户指南**》中的[移动对象](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

**注意**  
您无法更改现有函数的[部署包类型](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-PackageType)（.zip 或容器映像）。例如，您无法将容器映像函数转换为使用 .zip 文件归档。您必须创建新函数。

**创建新函数（控制台）**

1. 打开 Lambda 控制台的[“函数”页面](https://console.aws.amazon.com/lambda/home#/functions)，然后选择**创建函数**。

1. 选择**从头开始创作**。

1. 在**基本信息**中，执行以下操作：

   1. 对于**函数名称**，输入函数的名称。

   1. 对于**运行时系统**，选择要使用的运行时系统。

   1. （可选）对于**架构**，选择要用于函数的指令集架构。默认架构为 x86\$164。确保您的函数的 .zip 部署包与您选择的指令集架构兼容。

1. （可选）在 **Permissions**（权限）下，展开 **Change default execution role**（更改默认执行角色）。您可以创建新的**执行角色**，也可以使用现有角色。

1. 选择**创建函数**。Lambda 使用您选择的运行时系统创建基本“Hello world”函数。

**从本地计算机上传 .zip 归档（控制台）**

1. 在 Lambda 控制台的[“函数”页面](https://console.aws.amazon.com/lambda/home#/functions)中，选择要为其上传 .zip 文件的函数。

1. 选择**代码**选项卡。

1. 在**代码源**窗格中，选择**上传自**。

1. 选择 **.zip 文件**。

1. 要上传 .zip 文件，请执行以下操作：

   1. 选择**上传**，然后在文件选择器中选择您的 .zip 文件。

   1. 选择**打开**。

   1. 选择**保存**。

**从 Amazon S3 存储桶上传 .zip 归档（控制台）**

1. 在 Lambda 控制台的[“函数”页面](https://console.aws.amazon.com/lambda/home#/functions)中，选择要为其上传新 .zip 文件的函数。

1. 选择**代码**选项卡。

1. 在**代码源**窗格中，选择**上传自**。

1. 选择 **Amazon S3 位置**。

1. 粘贴 .zip 文件的 Amazon S3 链接 URL，然后选择**保存**。

### 使用控制台代码编辑器更新 .zip 文件函数
<a name="python-package-console-edit"></a>

 对于某些带有 .zip 部署包的函数，您可以使用 Lambda 控制台的内置代码编辑器直接更新函数代码。要使用此功能，函数必须满足以下条件：
+ 函数必须使用一种解释性语言运行时系统（Python、Node.js 或 Ruby）
+ 函数的部署包必须小于 50 MB（未压缩状态）。

带有容器映像部署包的函数的代码不能直接在控制台中编辑。

**要使用控制台代码编辑器更新函数代码。**

1. 打开 Lambda 控制台的[“函数”页面](https://console.aws.amazon.com/lambda/home#/functions)，然后选择函数。

1. 选择**代码**选项卡。

1. 在**代码源**窗格中，选择源代码文件并在集成的代码编辑器中对其进行编辑。

1. 在**部署**部分，选择**部署**以更新函数的代码：  
![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

### 使用 AWS CLI 通过 .zip 文件创建和更新函数
<a name="python-package-create-cli"></a>

 您可以使用 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 创建新函数或使用 .zip 文件更新现有函数。使用 [create-function](https://docs.aws.amazon.com/cli/latest/reference/lambda/create-function.html) 和 [update-function-code](https://docs.aws.amazon.com/cli/latest/reference/lambda/create-function.html) 命令部署 .zip 程序包。如果您的 .zip 文件小于 50MB，则可以从本地生成计算机上的文件位置上传 .zip 程序包。对于较大的文件，必须从 Amazon S3 存储桶上传 .zip 程序包。有关如何使用 AWS CLI 将文件上传到 Amazon S3 存储桶的说明，请参阅《AWS CLI 用户指南**》中的[移动对象](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

**注意**  
如果您使用 AWS CLI 从 Amazon S3 存储桶上传 .zip 文件，则该存储桶必须与您的函数位于同一个 AWS 区域 中。

 要通过 AWS CLI 使用 .zip 文件创建新函数，则必须指定以下内容：
+ 函数的名称 (`--function-name`)
+ 函数的运行时系统 (`--runtime`)
+ 函数的[执行角色](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html) (`--role`) 的 Amazon 资源名称（ARN）
+ 函数代码 (`--handler`) 中处理程序方法的名称

 还必须指定 .zip 文件的位置。如果 .zip 文件位于本地生成计算机上的文件夹中，请使用 `--zip-file` 选项指定文件路径，如以下示例命令所示。

```
aws lambda create-function --function-name myFunction \
--runtime python3.14 --handler lambda_function.lambda_handler \
--role arn:aws:iam::111122223333:role/service-role/my-lambda-role \
--zip-file fileb://myFunction.zip
```

 要指定 .zip 文件在 Amazon S3 存储桶中的位置，请使用 `--code` 选项，如以下示例命令所示。您只需对版本控制对象使用 `S3ObjectVersion` 参数。

```
aws lambda create-function --function-name myFunction \
--runtime python3.14 --handler lambda_function.lambda_handler \
--role arn:aws:iam::111122223333:role/service-role/my-lambda-role \
--code S3Bucket=amzn-s3-demo-bucket,S3Key=myFileName.zip,S3ObjectVersion=myObjectVersion
```

 要使用 CLI 更新现有函数，请使用 `--function-name` 参数指定函数的名称。您还必须指定要用于更新函数代码的 .zip 文件的位置。如果 .zip 文件位于本地生成计算机上的文件夹中，请使用 `--zip-file` 选项指定文件路径，如以下示例命令所示。

```
aws lambda update-function-code --function-name myFunction \
--zip-file fileb://myFunction.zip
```

 要指定 .zip 文件在 Amazon S3 存储桶中的位置，请使用 `--s3-bucket` 和 `--s3-key` 选项，如以下示例命令所示。您只需对版本控制对象使用 `--s3-object-version` 参数。

```
aws lambda update-function-code --function-name myFunction \
--s3-bucket amzn-s3-demo-bucket --s3-key myFileName.zip --s3-object-version myObject Version
```

### 使用 Lambda API 通过 .zip 文件创建和更新函数
<a name="python-package-create-api"></a>

 要使用 .zip 文件归档创建和更新函数，请使用以下 API 操作：
+ [CreateFunction](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html)
+ [UpdateFunctionCode](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateFunctionCode.html)

### 使用 AWS SAM 通过 .zip 文件创建和更新函数
<a name="python-package-create-sam"></a>

 AWS Serverless Application Model（AWS SAM）是一个工具包，可帮助简化在 AWS 上构建和运行无服务器应用程序的过程。您可以在 YAML 或 JSON 模板中为应用程序定义资源，并使用 AWS SAM 命令行界面（AWS SAM CLI）构建、打包和部署应用程序。当您通过 AWS SAM 模板构建 Lambda 函数时，AWS SAM 会使用您的函数代码和您指定的任何依赖项自动创建 .zip 部署包或容器映像。要了解有关使用 AWS SAM 构建和部署 Lambda 函数的更多信息，请参阅《AWS Serverless Application Model 开发人员指南**》中的 [AWS SAM 入门](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started.html)。

您可以使用 AWS SAM 创建使用现有 .zip 文件归档的 Lambda 函数。要使用 AWS SAM 创建 Lambda 函数，您可以将 .zip 文件保存在 Amazon S3 存储桶或生成计算机上的本地文件夹中。有关如何使用 AWS CLI 将文件上传到 Amazon S3 存储桶的说明，请参阅《AWS CLI 用户指南**》中的[移动对象](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

 在 AWS SAM 模板中，`AWS::Serverless::Function` 资源将指定 Lambda 函数。在此资源中，设置以下属性以创建使用 .zip 文件归档的函数：
+ `PackageType` – 设置为 `Zip`
+ `CodeUri` – 设置为函数代码的 Amazon S3 URI、本地文件夹的路径或 [FunctionCode](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-functioncode.html) 对象
+ `Runtime` – 设置为您选择的运行时系统

 使用 AWS SAM，如果 .zip 文件大于 50MB，则不需要先将其上传到 Amazon S3 存储桶。AWS SAM 可以从本地生成计算机上的某个位置上传最大允许大小为 250MB（已解压缩）的 .zip 程序包。

 要了解有关在 AWS SAM 中使用 .zip 文件部署函数的更多信息，请参阅《AWS SAM 开发人员指南**》中的 [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)。

### 使用 CloudFormation 通过 .zip 文件创建和更新函数
<a name="python-package-create-cfn"></a>

 您可以使用 CloudFormation 创建使用 .zip 文件归档的 Lambda 函数。要从 .zip 文件创建 Lambda 函数，必须先将您的文件上传到 Amazon S3 存储桶。有关如何使用 AWS CLI 将文件上传到 Amazon S3 存储桶的说明，请参阅《AWS CLI 用户指南**》中的[移动对象](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

对于 Node.js 和 Python 运行时系统，您还可以在 CloudFormation 模板中提供内联源代码。然后 CloudFormation 会在您构建函数时创建包含代码的 .zip 文件。

**使用现有 .zip 文件**

在 CloudFormation 模板中，`AWS::Lambda::Function` 资源将指定 Lambda 函数。在此资源中，设置以下属性以创建使用 .zip 文件归档的函数：
+ `PackageType` – 设置为 `Zip`
+ `Code` – 在 `S3Bucket` 和 `S3Key` 字段中输入 Amazon S3 存储桶名称和 .zip 文件名。
+ `Runtime` – 设置为您选择的运行时系统

**从内联代码创建 .zip 文件**

您可以在 CloudFormation 模板中声明使用 Python 或 Node.js 内联编写的简单函数。由于代码嵌入在 YAML 或 JSON 中，因此您无法向部署包添加任何外部依赖关系。这意味着您的函数必须使用运行时系统中包含的 AWS SDK 版本。模板的要求（例如必须转义某些字符）也让使用 IDE 的语法检查和代码完成功能变得更加困难。这意味着模板可能需要额外的测试。由于这些限制，内联声明函数最适合用于不经常更改的非常简单的代码。

要从 Node.js 和 Python 运行时系统的内联代码创建 .zip 文件，请在模板的 `AWS::Lambda::Function` 资源中设置以下属性：
+ `PackageType` – 设置为 `Zip`
+ `Code` – 在 `ZipFile` 字段中输入函数代码
+ `Runtime` – 设置为您选择的运行时系统

 CloudFormation 生成的 .zip 文件不能超过 4MB。要了解有关在 CloudFormation 中使用 .zip 文件部署函数的更多信息，请参阅《CloudFormation 用户指南**》中的 [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)。

# 使用容器镜像部署 Python Lambda 函数
<a name="python-image"></a>

有三种方法可以为 Python Lambda 函数构建容器映像：
+ [使用 Python 的 AWS 基本映像](#python-image-instructions)

  [AWS 基本映像](images-create.md#runtimes-images-lp)会预加载一个语言运行时系统、一个用于管理 Lambda 和函数代码之间交互的运行时系统接口客户端，以及一个用于本地测试的运行时系统接口仿真器。
+ [使用 AWS 仅限操作系统的基础镜像](images-create.md#runtimes-images-provided)

  [AWS 仅限操作系统的运行时系统](https://gallery.ecr.aws/lambda/provided)包含 Amazon Linux 发行版和[运行时系统接口模拟器](https://github.com/aws/aws-lambda-runtime-interface-emulator/)。这些镜像通常用于为编译语言（例如 [Go](go-image.md#go-image-provided) 和 [Rust](lambda-rust.md)）以及 Lambda 未提供基础映像的语言或语言版本（例如 Node.js 19）创建容器镜像。您也可以使用仅限操作系统的基础映像来实施[自定义运行时系统](runtimes-custom.md)。要使映像与 Lambda 兼容，您必须在映像中包含 [Python 的运行时系统接口客户端](#python-image-clients)。
+ [使用非 AWS 基本映像](#python-image-clients)

  您还可以使用其他容器注册表的备用基本映像，例如 Alpine Linux 或 Debian。您还可以使用您的组织创建的自定义映像。要使映像与 Lambda 兼容，您必须在映像中包含 [Python 的运行时系统接口客户端](#python-image-clients)。

**提示**  
要缩短 Lambda 容器函数激活所需的时间，请参阅 Docker 文档中的[使用多阶段构建](https://docs.docker.com/build/building/multi-stage/)。要构建高效的容器映像，请遵循[编写 Dockerfiles 的最佳实践](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)。

此页面介绍了如何为 Lambda 构建、测试和部署容器映像。

**Topics**
+ [Python AWS 基本映像](#python-image-base)
+ [使用 Python 的 AWS 基本映像](#python-image-instructions)
+ [将备用基本映像与运行时系统接口客户端配合使用](#python-image-clients)

## Python AWS 基本映像
<a name="python-image-base"></a>

AWS为 Python 提供了以下基本映像：


| 标签 | 运行时 | 操作系统 | Dockerfile | 弃用 | 
| --- | --- | --- | --- | --- | 
| 3.14 | Python 3.14 | Amazon Linux 2023 | [GitHub 上适用于 Python 3.14 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/python3.14/Dockerfile.python3.14) |   2029 年 6 月 30 日   | 
| 3.13 | Python 3.13 | Amazon Linux 2023 | [GitHub 上适用于 Python 3.13 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/python3.13/Dockerfile.python3.13) |   2029 年 6 月 30 日   | 
| 3.12 | Python 3.12 | Amazon Linux 2023 | [GitHub 上适用于 Python 3.12 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/python3.12/Dockerfile.python3.12) |   2028 年 10 月 31 日   | 
| 3.11 | Python 3.11 | Amazon Linux 2 | [GitHub 上适用于 Python 3.11 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/python3.11/Dockerfile.python3.11) |   2027 年 6 月 30 日   | 
| 3.10 | Python 3.10 | Amazon Linux 2 | [GitHub 上适用于 Python 3.10 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/python3.10/Dockerfile.python3.10) |   2026 年 10 月 31 日   | 

Amazon ECR 存储库：[gallery.ecr.aws/lambda/python](https://gallery.ecr.aws/lambda/python)

Python 3.12 及更高版本的基础映像基于 [Amazon Linux 2023 最小容器映像](https://docs.aws.amazon.com/linux/al2023/ug/minimal-container.html)。Python 3.8-3.11 基础映像基于 Amazon Linux 2 映像。与 Amazon Linux 2 相比，基于 AL2023 的映像具有多项优势，包括较小的部署占用空间以及 `glibc` 等更新版本的库。

基于 AL2023 的映像使用 `microdnf`（符号链接为 `dnf`）作为软件包管理器，而不是 Amazon Linux 2 中的默认软件包管理器 `yum`。`microdnf` 是 `dnf` 的独立实现。有关基于 AL2023 的映像中已包含软件包的列表，请参阅[比较 Amazon Linux 2023 容器映像上安装的软件包](https://docs.aws.amazon.com/linux/al2023/ug/al2023-container-image-types.html)中的**最小容器**列。有关 AL2023 和 Amazon Linux 2 之间区别的更多信息，请参阅 AWS Compute Blog 上的 [Introducing the Amazon Linux 2023 runtime for AWS Lambda](https://aws.amazon.com/blogs/compute/introducing-the-amazon-linux-2023-runtime-for-aws-lambda/)。

**注意**  
要在本地运行基于 AL2023 的映像，包括使用 AWS Serverless Application Model（AWS SAM），您必须使用 Docker 版本 20.10.10 或更高版本。

### 基本映像中的依赖项搜索路径
<a name="python-image-searchpath"></a>

在代码中使用 `import` 语句时，Python 运行时系统会搜索其搜索路径中的目录，直到找到相应模块或包。默认情况下，运行时系统会首先搜索 `{LAMBDA_TASK_ROOT}` 目录。如果映像含有包含运行时系统的库的某个版本，则此版本将优先于运行时系统中包含的版本。

搜索路径中的其他步骤取决于您使用的 Python Lambda 基本映像的版本：
+ **Python 3.11 及更高版本**：包含运行时系统的库和安装了 pip 的库均安装在 `/var/lang/lib/python3.11/site-packages` 目录中。此目录优先于搜索路径中的 `/var/runtime`。您可以通过使用 pip 安装更新版本来覆盖 SDK。您可以使用 pip 来验证包含运行时系统的 SDK 及其依赖项是否与您安装的任何程序包兼容。
+ **Python 3.8-3.10**：包含运行时系统的库安装在 `/var/runtime` 目录中。安装了 pip 的库安装在 `/var/lang/lib/python3.x/site-packages` 目录中。此 `/var/runtime` 目录优先于搜索路径中的 `/var/lang/lib/python3.x/site-packages`。

通过添加以下代码段，您可以查看 Lambda 函数的完整搜索路径。

```
import sys
      
search_path = sys.path
print(search_path)
```

## 使用 Python 的 AWS 基本映像
<a name="python-image-instructions"></a>

### 先决条件
<a name="python-image-prerequisites"></a>

要完成本节中的步骤，您必须满足以下条件：
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [Docker](https://docs.docker.com/get-docker)（最低版本 25.0.0）
+ Docker [buildx 插件](https://github.com/docker/buildx/blob/master/README.md)。
+ Python

### 从基本映像创建映像
<a name="python-image-create"></a>

**要从 Python 的 AWS 的基本映像创建容器映像**

1. 为项目创建一个目录，然后切换到该目录。

   ```
   mkdir example
   cd example
   ```

1. 创建名为 `lambda_function.py` 的新文件。您可以将以下示例函数代码添加到文件中进行测试，也可以使用您自己的函数代码。  
**Example Python 函数**  

   ```
   import sys
   def handler(event, context):
       return 'Hello from AWS Lambda using Python' + sys.version + '!'
   ```

1. 创建名为 `requirements.txt` 的新文件。如果您使用的是上一步中的示例函数代码，则可以将文件留空，因为没有依赖项。否则，请列出每个必需的库。例如，如果您的函数使用的是 适用于 Python (Boto3) 的 AWS SDK，则 `requirements.txt` 应如下所示：  
**Example requirements.txt**  

   ```
   boto3
   ```

1. 使用以下配置创建一个新的 Dockerfile。
   + 将 `FROM` 属性设置为[基本映像的 URI](https://gallery.ecr.aws/lambda/python/)。
   + 使用 COPY 命令将函数代码和运行时系统依赖项复制到 `{LAMBDA_TASK_ROOT}`，此为 [Lambda 定义的环境变量](configuration-envvars.md#configuration-envvars-runtime)。
   + 将 `CMD` 参数设置为 Lambda 函数处理程序。

   请注意，示例 Dockerfile 不包含 [USER 指令](https://docs.docker.com/reference/dockerfile/#user)。当您将容器映像部署到 Lambda 时，Lambda 会自动定义具有最低权限的默认 Linux 用户。这与标准 Docker 行为不同，标准 Docker 在未提供 `USER` 指令时默认为 `root` 用户。  
**Example Dockerfile**  

   ```
   FROM public.ecr.aws/lambda/python:3.12
   
   # Copy requirements.txt
   COPY requirements.txt ${LAMBDA_TASK_ROOT}
   
   # Install the specified packages
   RUN pip install -r requirements.txt
   
   # Copy function code
   COPY lambda_function.py ${LAMBDA_TASK_ROOT}
   
   # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
   CMD [ "lambda_function.handler" ]
   ```

1. 使用 [docker build](https://docs.docker.com/engine/reference/commandline/build/) 命令构建 Docker 映像。以下示例将映像命名为 `docker-image` 并为其提供 `test` [标签](https://docs.docker.com/engine/reference/commandline/build/#tag)。要使您的映像与 Lambda 兼容，您必须使用 `--provenance=false` 选项。

   ```
   docker buildx build --platform linux/amd64 --provenance=false -t docker-image:test .
   ```
**注意**  
该命令指定了 `--platform linux/amd64` 选项，可确保无论生成计算机的架构如何，容器始终与 Lambda 执行环境兼容。如果打算使用 ARM64 指令集架构创建 Lambda 函数，请务必将命令更改为使用 `--platform linux/arm64` 选项。

### （可选）在本地测试映像
<a name="python-image-test"></a>

1. 使用 **docker run** 命令启动 Docker 映像。在此示例中，`docker-image` 是映像名称，`test` 是标签。

   ```
   docker run --platform linux/amd64 -p 9000:8080 docker-image:test
   ```

   此命令会将映像作为容器运行，并在 `localhost:9000/2015-03-31/functions/function/invocations` 创建本地端点。
**注意**  
如果为 ARM64 指令集架构创建 Docker 映像，请务必使用 `--platform linux/arm64` 选项，而不是 `--platform linux/amd64` 选项。

1. 在新的终端窗口中，将事件发布到本地端点。

------
#### [ Linux/macOS ]

   在 Linux 和 macOS 中，运行以下 `curl` 命令：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
   ```

   此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码，则可能需要使用 JSON 负载调用函数。示例：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
   ```

------
#### [ PowerShell ]

   在 PowerShell 中，运行以下 `Invoke-WebRequest` 命令：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"
   ```

   此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码，则可能需要使用 JSON 负载调用函数。示例：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
   ```

------

1. 获取容器 ID。

   ```
   docker ps
   ```

1. 使用 [docker kill](https://docs.docker.com/engine/reference/commandline/kill/) 命令停止容器。在此命令中，将 `3766c4ab331c` 替换为上一步中的容器 ID。

   ```
   docker kill 3766c4ab331c
   ```

### 部署映像
<a name="python-image-deploy"></a>

**将映像上传到 Amazon ECR 并创建 Lambda 函数**

1. 运行 [get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html) 命令，以针对 Amazon ECR 注册表进行 Docker CLI 身份验证。
   + 将 `--region` 值设置为要在其中创建 Amazon ECR 存储库的 AWS 区域。
   + 将 `111122223333` 替换为您的 AWS 账户 ID。

   ```
   aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
   ```

1. 使用 [create-repository](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html) 命令在 Amazon ECR 中创建存储库。

   ```
   aws ecr create-repository --repository-name hello-world --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
   ```
**注意**  
Amazon ECR 存储库必须与 Lambda 函数位于同一 AWS 区域 内。

   如果成功，您将会看到如下响应：

   ```
   {
       "repository": {
           "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world",
           "registryId": "111122223333",
           "repositoryName": "hello-world",
           "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world",
           "createdAt": "2023-03-09T10:39:01+00:00",
           "imageTagMutability": "MUTABLE",
           "imageScanningConfiguration": {
               "scanOnPush": true
           },
           "encryptionConfiguration": {
               "encryptionType": "AES256"
           }
       }
   }
   ```

1. 从上一步的输出中复制 `repositoryUri`。

1. 运行 [docker tag](https://docs.docker.com/engine/reference/commandline/tag/) 命令，将本地映像作为最新版本标记到 Amazon ECR 存储库中。在此命令中：
   + `docker-image:test` 是 Docker 映像的名称和[标签](https://docs.docker.com/engine/reference/commandline/build/#tag)。这是您在 `docker build` 命令中指定的映像名称和标签。
   + 将 `<ECRrepositoryUri>` 替换为复制的 `repositoryUri`。确保 URI 末尾包含 `:latest`。

   ```
   docker tag docker-image:test <ECRrepositoryUri>:latest
   ```

   示例：

   ```
   docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. 运行 [docker push](https://docs.docker.com/engine/reference/commandline/push/) 命令，以将本地映像部署到 Amazon ECR 存储库。确保存储库 URI 末尾包含 `:latest`。

   ```
   docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. 如果您还没有函数的执行角色，请[创建执行角色](lambda-intro-execution-role.md#permissions-executionrole-api)。在下一步中，您需要提供角色的 Amazon 资源名称（ARN）。

1. 创建 Lambda 函数。对于 `ImageUri`，指定之前的存储库 URI。确保 URI 末尾包含 `:latest`。

   ```
   aws lambda create-function \
     --function-name hello-world \
     --package-type Image \
     --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
     --role arn:aws:iam::111122223333:role/lambda-ex
   ```
**注意**  
只要映像与 Lambda 函数位于同一区域内，您就可以使用其他 AWS 账户中的映像创建函数。有关更多信息，请参阅 [Amazon ECR 跨账户权限](images-create.md#configuration-images-xaccount-permissions)。

1. 调用函数。

   ```
   aws lambda invoke --function-name hello-world response.json
   ```

   应出现如下响应：

   ```
   {
     "ExecutedVersion": "$LATEST", 
     "StatusCode": 200
   }
   ```

1. 要查看函数的输出，请检查 `response.json` 文件。

要更新函数代码，您必须再次构建映像，将新映像上传到 Amazon ECR 存储库，然后使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令将映像部署到 Lambda 函数。

Lambda 会将映像标签解析为特定的映像摘要。这意味着，如果您将用于部署函数的映像标签指向 Amazon ECR 中的新映像，则 Lambda 不会自动更新该函数以使用新映像。

要将新映像部署到相同的 Lambda 函数，即使 Amazon ECR 中的映像标签保持不变，也必须使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令。在以下示例中，`--publish` 选项使用更新的容器映像创建函数的新版本。

```
aws lambda update-function-code \
  --function-name hello-world \
  --image-uri 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
  --publish
```

## 将备用基本映像与运行时系统接口客户端配合使用
<a name="python-image-clients"></a>

如果使用[仅限操作系统的基础映像](images-create.md#runtimes-images-provided)或者备用基础映像，则必须在映像中包括运行时系统接口客户端。运行时系统接口客户端可扩展 [运行时 API](runtimes-api.md)，用于管理 Lambda 和函数代码之间的交互。

使用 pip 程序包管理器安装 [Python 的运行时系统接口客户端](https://pypi.org/project/awslambdaric)：

```
pip install awslambdaric
```

您还可以从 GitHub 下载 [Python 运行时接口客户端](https://github.com/aws/aws-lambda-python-runtime-interface-client/)。

以下示例演示了如何使用非 AWS 基本映像为 Python 构建容器映像。示例 Dockerfile 使用官方 Python 基本映像。Dockerfile 包含 Python 的运行时系统接口客户端。

### 先决条件
<a name="python-alt-prerequisites"></a>

要完成本节中的步骤，您必须满足以下条件：
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [Docker](https://docs.docker.com/get-docker)（最低版本 25.0.0）
+ Docker [buildx 插件](https://github.com/docker/buildx/blob/master/README.md)。
+ Python

### 从备用基本映像创建映像
<a name="python-alt-create"></a>

**要从非 AWS 基本映像创建容器映像**

1. 为项目创建一个目录，然后切换到该目录。

   ```
   mkdir example
   cd example
   ```

1. 创建名为 `lambda_function.py` 的新文件。您可以将以下示例函数代码添加到文件中进行测试，也可以使用您自己的函数代码。  
**Example Python 函数**  

   ```
   import sys
   def handler(event, context):
       return 'Hello from AWS Lambda using Python' + sys.version + '!'
   ```

1. 创建名为 `requirements.txt` 的新文件。如果您使用的是上一步中的示例函数代码，则可以将文件留空，因为没有依赖项。否则，请列出每个必需的库。例如，如果您的函数使用的是 适用于 Python (Boto3) 的 AWS SDK，则 `requirements.txt` 应如下所示：  
**Example requirements.txt**  

   ```
   boto3
   ```

1. 创建新 Dockerfile。以下 Dockerfile 使用官方 Python 基本映像而不是 [AWS 基本映像](images-create.md#runtimes-images-lp)。Dockerfile 包含[运行时系统接口客户端](https://pypi.org/project/awslambdaric)，该客户端可使映像与 Lambda 兼容。以下示例 Dockerfile 将使用[多阶段构建](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#use-multi-stage-builds)。
   + 将 `FROM` 属性设置为基本映像。
   + 将 `ENTRYPOINT` 设置为您希望 Docker 容器在启动时运行的模块。在本例中，模块为运行时系统接口客户端。
   + 将 `CMD` 设置为 Lambda 函数处理程序。

   请注意，示例 Dockerfile 不包含 [USER 指令](https://docs.docker.com/reference/dockerfile/#user)。当您将容器映像部署到 Lambda 时，Lambda 会自动定义具有最低权限的默认 Linux 用户。这与标准 Docker 行为不同，标准 Docker 在未提供 `USER` 指令时默认为 `root` 用户。  
**Example Dockerfile**  

   ```
   # Define custom function directory
   ARG FUNCTION_DIR="/function"
   
   FROM python:3.12 AS build-image
   
   # Include global arg in this stage of the build
   ARG FUNCTION_DIR
   
   # Copy function code
   RUN mkdir -p ${FUNCTION_DIR}
   COPY . ${FUNCTION_DIR}
   
   # Install the function's dependencies
   RUN pip install \
       --target ${FUNCTION_DIR} \
           awslambdaric
   
   # Use a slim version of the base Python image to reduce the final image size
   FROM python:3.12-slim
   
   # Include global arg in this stage of the build
   ARG FUNCTION_DIR
   # Set working directory to function root directory
   WORKDIR ${FUNCTION_DIR}
   
   # Copy in the built dependencies
   COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
   
   # Set runtime interface client as default command for the container runtime
   ENTRYPOINT [ "/usr/local/bin/python", "-m", "awslambdaric" ]
   # Pass the name of the function handler as an argument to the runtime
   CMD [ "lambda_function.handler" ]
   ```

1. 使用 [docker build](https://docs.docker.com/engine/reference/commandline/build/) 命令构建 Docker 映像。以下示例将映像命名为 `docker-image` 并为其提供 `test` [标签](https://docs.docker.com/engine/reference/commandline/build/#tag)。要使您的映像与 Lambda 兼容，您必须使用 `--provenance=false` 选项。

   ```
   docker buildx build --platform linux/amd64 --provenance=false -t docker-image:test .
   ```
**注意**  
该命令指定了 `--platform linux/amd64` 选项，可确保无论生成计算机的架构如何，容器始终与 Lambda 执行环境兼容。如果打算使用 ARM64 指令集架构创建 Lambda 函数，请务必将命令更改为使用 `--platform linux/arm64` 选项。

### （可选）在本地测试映像
<a name="python-alt-test"></a>

使用[运行时系统接口仿真器](https://github.com/aws/aws-lambda-runtime-interface-emulator/)在本地测试映像。您可以[将仿真器构建到映像中](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#build-rie-into-your-base-image)，也可以使用以下程序将其安装在本地计算机上。

**在本地计算机上安装并运行运行时系统接口仿真器**

1. 从项目目录中，运行以下命令以从 GitHub 下载运行时系统接口仿真器（x86-64 架构）并将其安装在本地计算机上。

------
#### [ Linux/macOS ]

   ```
   mkdir -p ~/.aws-lambda-rie && \
       curl -Lo ~/.aws-lambda-rie/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && \
       chmod +x ~/.aws-lambda-rie/aws-lambda-rie
   ```

   要安装 arm64 仿真器，请将上一条命令中的 GitHub 存储库 URL 替换为以下内容：

   ```
   https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
   ```

------
#### [ PowerShell ]

   ```
   $dirPath = "$HOME\.aws-lambda-rie"
   if (-not (Test-Path $dirPath)) {
       New-Item -Path $dirPath -ItemType Directory
   }
         
   $downloadLink = "https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie"
   $destinationPath = "$HOME\.aws-lambda-rie\aws-lambda-rie"
   Invoke-WebRequest -Uri $downloadLink -OutFile $destinationPath
   ```

   要安装 arm64 模拟器，请将 `$downloadLink` 替换为以下内容：

   ```
   https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
   ```

------

1. 使用 **docker run** 命令启动 Docker 映像。请注意以下几点：
   + `docker-image` 是映像名称，`test` 是标签。
   + `/usr/local/bin/python -m awslambdaric lambda_function.handler` 是 `ENTRYPOINT`，后跟您 Dockerfile 中的 `CMD`。

------
#### [ Linux/macOS ]

   ```
   docker run --platform linux/amd64 -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \
       --entrypoint /aws-lambda/aws-lambda-rie \
       docker-image:test \
           /usr/local/bin/python -m awslambdaric lambda_function.handler
   ```

------
#### [ PowerShell ]

   ```
   docker run --platform linux/amd64 -d -v "$HOME\.aws-lambda-rie:/aws-lambda" -p 9000:8080 `
   --entrypoint /aws-lambda/aws-lambda-rie `
   docker-image:test `
       /usr/local/bin/python -m awslambdaric lambda_function.handler
   ```

------

   此命令会将映像作为容器运行，并在 `localhost:9000/2015-03-31/functions/function/invocations` 创建本地端点。
**注意**  
如果为 ARM64 指令集架构创建 Docker 映像，请务必使用 `--platform linux/arm64` 选项，而不是 `--platform linux/amd64` 选项。

1. 将事件发布到本地端点。

------
#### [ Linux/macOS ]

   在 Linux 和 macOS 中，运行以下 `curl` 命令：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
   ```

   此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码，则可能需要使用 JSON 负载调用函数。示例：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
   ```

------
#### [ PowerShell ]

   在 PowerShell 中，运行以下 `Invoke-WebRequest` 命令：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"
   ```

   此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码，则可能需要使用 JSON 负载调用函数。示例：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
   ```

------

1. 获取容器 ID。

   ```
   docker ps
   ```

1. 使用 [docker kill](https://docs.docker.com/engine/reference/commandline/kill/) 命令停止容器。在此命令中，将 `3766c4ab331c` 替换为上一步中的容器 ID。

   ```
   docker kill 3766c4ab331c
   ```

### 部署映像
<a name="python-alt-deploy"></a>

**将映像上传到 Amazon ECR 并创建 Lambda 函数**

1. 运行 [get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html) 命令，以针对 Amazon ECR 注册表进行 Docker CLI 身份验证。
   + 将 `--region` 值设置为要在其中创建 Amazon ECR 存储库的 AWS 区域。
   + 将 `111122223333` 替换为您的 AWS 账户 ID。

   ```
   aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
   ```

1. 使用 [create-repository](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html) 命令在 Amazon ECR 中创建存储库。

   ```
   aws ecr create-repository --repository-name hello-world --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
   ```
**注意**  
Amazon ECR 存储库必须与 Lambda 函数位于同一 AWS 区域 内。

   如果成功，您将会看到如下响应：

   ```
   {
       "repository": {
           "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world",
           "registryId": "111122223333",
           "repositoryName": "hello-world",
           "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world",
           "createdAt": "2023-03-09T10:39:01+00:00",
           "imageTagMutability": "MUTABLE",
           "imageScanningConfiguration": {
               "scanOnPush": true
           },
           "encryptionConfiguration": {
               "encryptionType": "AES256"
           }
       }
   }
   ```

1. 从上一步的输出中复制 `repositoryUri`。

1. 运行 [docker tag](https://docs.docker.com/engine/reference/commandline/tag/) 命令，将本地映像作为最新版本标记到 Amazon ECR 存储库中。在此命令中：
   + `docker-image:test` 是 Docker 映像的名称和[标签](https://docs.docker.com/engine/reference/commandline/build/#tag)。这是您在 `docker build` 命令中指定的映像名称和标签。
   + 将 `<ECRrepositoryUri>` 替换为复制的 `repositoryUri`。确保 URI 末尾包含 `:latest`。

   ```
   docker tag docker-image:test <ECRrepositoryUri>:latest
   ```

   示例：

   ```
   docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. 运行 [docker push](https://docs.docker.com/engine/reference/commandline/push/) 命令，以将本地映像部署到 Amazon ECR 存储库。确保存储库 URI 末尾包含 `:latest`。

   ```
   docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
   ```

1. 如果您还没有函数的执行角色，请[创建执行角色](lambda-intro-execution-role.md#permissions-executionrole-api)。在下一步中，您需要提供角色的 Amazon 资源名称（ARN）。

1. 创建 Lambda 函数。对于 `ImageUri`，指定之前的存储库 URI。确保 URI 末尾包含 `:latest`。

   ```
   aws lambda create-function \
     --function-name hello-world \
     --package-type Image \
     --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
     --role arn:aws:iam::111122223333:role/lambda-ex
   ```
**注意**  
只要映像与 Lambda 函数位于同一区域内，您就可以使用其他 AWS 账户中的映像创建函数。有关更多信息，请参阅 [Amazon ECR 跨账户权限](images-create.md#configuration-images-xaccount-permissions)。

1. 调用函数。

   ```
   aws lambda invoke --function-name hello-world response.json
   ```

   应出现如下响应：

   ```
   {
     "ExecutedVersion": "$LATEST", 
     "StatusCode": 200
   }
   ```

1. 要查看函数的输出，请检查 `response.json` 文件。

要更新函数代码，您必须再次构建映像，将新映像上传到 Amazon ECR 存储库，然后使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令将映像部署到 Lambda 函数。

Lambda 会将映像标签解析为特定的映像摘要。这意味着，如果您将用于部署函数的映像标签指向 Amazon ECR 中的新映像，则 Lambda 不会自动更新该函数以使用新映像。

要将新映像部署到相同的 Lambda 函数，即使 Amazon ECR 中的映像标签保持不变，也必须使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令。在以下示例中，`--publish` 选项使用更新的容器映像创建函数的新版本。

```
aws lambda update-function-code \
  --function-name hello-world \
  --image-uri 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \
  --publish
```

对于如何从 Alpine 基本镜像创建 Python 镜像的示例，请参阅AWS博客上的 [Lambda 容器镜像支持](https://aws.amazon.com/blogs/aws/new-for-aws-lambda-container-image-support/)。

# 使用 Python Lambda 函数的层
<a name="python-layers"></a>

使用 [Lambda 层](chapter-layers.md)来打包要在多个函数中重复使用的代码和依赖项。层通常包含库依赖项、[自定义运行时系统](runtimes-custom.md)或配置文件。创建层涉及三个常见步骤：

1. 打包层内容。此步骤需要创建 .zip 文件存档，其中包含要在函数中使用的依赖项。

1. 在 Lambda 中创建层。

1. 将层添加到函数。

**Topics**
+ [打包层内容](#python-layers-package)
+ [在 Lambda 中创建层](#publishing-layer)
+ [将层添加到函数](#python-layer-adding)
+ [示例应用程序](#python-layer-sample-app)

## 打包层内容
<a name="python-layers-package"></a>

要创建层，请将您的包捆绑到满足以下要求的 .zip 文件存档中：
+ 使用计划用于 Lambda 函数的相同 Python 版本来构建层。例如，如果您使用 Python 3.14 构建层，则您的函数应使用 Python 3.14 运行时。
+ 您的 .zip 文件必须包含根级 `python` 目录。
+ 您的层中的包必须与 Linux 兼容。Lambda 函数在 Amazon Linux 上运行。

您可以创建包含使用 `pip` 安装的第三方 Python 库（例如 `requests` 或 `pandas`）或您自己的 Python 模块和包的层。

### 第三方依赖项
<a name="python-layers-third-party-dependencies"></a>

**使用 pip 包创建层**

1. 选择以下方法之一，将 `pip` 包安装到所需的顶级目录（`python/`）：

------
#### [ pip install ]

   对于纯 Python 包（如 requests 或 boto3）：

   ```
   pip install requests -t python/
   ```

   某些 Python 包（如 NumPy 和 Pandas）包含编译后的 C 组件。如果您要在 macOS 或 Windows 上使用这些包构建层，则可能需要使用以下命令来安装兼容 Linux 的 wheel 包：

   ```
   pip install numpy --platform manylinux2014_x86_64 --only-binary=:all: -t python/
   ```

   有关使用包含已编译组件的 Python 包的更多信息，请参阅[使用原生库创建 .zip 部署包](python-package.md#python-package-native-libraries)。

------
#### [ requirements.txt ]

   使用 `requirements.txt` 文件可以帮助您管理包版本并确保安装的一致性。

**Example requirements.txt**  

   ```
   requests==2.31.0
   boto3==1.37.34
   numpy==1.26.4
   ```

   如果您的 `requirements.txt` 文件只包含纯 Python 包（如 requests 或 boto3）：

   ```
   pip install -r requirements.txt -t python/
   ```

   某些 Python 包（如 NumPy 和 Pandas）包含编译后的 C 组件。如果您要在 macOS 或 Windows 上使用这些包构建层，则可能需要使用以下命令来安装兼容 Linux 的 wheel 包：

   ```
   pip install -r requirements.txt --platform manylinux2014_x86_64 --only-binary=:all: -t python/
   ```

   有关使用包含已编译组件的 Python 包的更多信息，请参阅[使用原生库创建 .zip 部署包](python-package.md#python-package-native-libraries)。

------

1. 压缩 `python` 目录中的内容。

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip python/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\python -DestinationPath .\layer.zip
   ```

------

   您的 .zip 文件的目录结构应如下所示：

   ```
   python/              # Required top-level directory
   └── requests/
   └── boto3/
   └── numpy/
   └── (dependencies of the other packages)
   ```
**注意**  
如果您使用 Python 虚拟环境（venv）来安装包，则目录结构将有所不同（例如，`python/lib/python3.x/site-packages`）。只要您的 .zip 文件包含根级 `python` 目录，Lambda 就可以找到并导入您的包。

### 自定义 Python 模块
<a name="custom-python-modules"></a>

**使用您自己的代码创建层**

1. 为您的层创建所需的顶级目录：

   ```
   mkdir python
   ```

1. 在 `python` 目录中创建您的 Python 模块。以下示例模块通过确认订单包含所需信息来验证订单。  
**Example 自定义模块：validator.py**  

   ```
   import json
   
   def validate_order(order_data):
       """Validates an order and returns formatted data."""
       required_fields = ['product_id', 'quantity']
       
       # Check required fields
       missing_fields = [field for field in required_fields if field not in order_data]
       if missing_fields:
           raise ValueError(f"Missing required fields: {', '.join(missing_fields)}")
       
       # Validate quantity
       quantity = order_data['quantity']
       if not isinstance(quantity, int) or quantity < 1:
           raise ValueError("Quantity must be a positive integer")
       
       # Format and return the validated data
       return {
           'product_id': str(order_data['product_id']),
           'quantity': quantity,
           'shipping_priority': order_data.get('priority', 'standard')
       }
   
   def format_response(status_code, body):
       """Formats the API response."""
       return {
           'statusCode': status_code,
           'body': json.dumps(body)
       }
   ```

1. 压缩 `python` 目录中的内容。

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip python/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\python -DestinationPath .\layer.zip
   ```

------

   您的 .zip 文件的目录结构应如下所示：

   ```
   python/     # Required top-level directory
   └── validator.py
   ```

1. 在您的函数中，像处理任何 Python 包一样导入和使用这些模块。示例：

   ```
   from validator import validate_order, format_response
   import json
   
   def lambda_handler(event, context):
       try:
           # Parse the order data from the event body
           order_data = json.loads(event.get('body', '{}'))
           
           # Validate and format the order
           validated_order = validate_order(order_data)
           
           return format_response(200, {
               'message': 'Order validated successfully',
               'order': validated_order
           })
       except ValueError as e:
           return format_response(400, {
               'error': str(e)
           })
       except Exception as e:
           return format_response(500, {
               'error': 'Internal server error'
           })
   ```

   您可以使用以下[测试事件](testing-functions.md#invoke-with-event)调用函数：

   ```
   {
       "body": "{\"product_id\": \"ABC123\", \"quantity\": 2, \"priority\": \"express\"}"
   }
   ```

   预期的回应：

   ```
   {
     "statusCode": 200,
     "body": "{\"message\": \"Order validated successfully\", \"order\": {\"product_id\": \"ABC123\", \"quantity\": 2, \"shipping_priority\": \"express\"}}"
   }
   ```

## 在 Lambda 中创建层
<a name="publishing-layer"></a>

您可以使用 AWS CLI 或 Lambda 控制台发布层。

------
#### [ AWS CLI ]

运行 [publish-layer-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-layer-version.html) AWS CLI 命令以创建 Lambda 层：

```
aws lambda publish-layer-version --layer-name my-layer --zip-file fileb://layer.zip --compatible-runtimes python3.14
```

[兼容的运行时](https://docs.aws.amazon.com/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)参数是可选的。指定后，Lambda 将使用此参数在 Lambda 控制台中筛选层。

------
#### [ Console ]

**创建层（控制台）**

1. 打开 Lambda 控制台的 [Layers page](https://console.aws.amazon.com/lambda/home#/layers)（层页面）。

1. 选择 **Create layer**（创建层）。

1. 选择**上传 .zip 文件**，然后上传您之前创建的 .zip 存档。

1. （可选）对于**兼容的运行时**，请选择与您用于构建层的 Python 版本相对应的 Python 运行时。

1. 选择**创建**。

------

## 将层添加到函数
<a name="python-layer-adding"></a>

------
#### [ AWS CLI ]

要将层附加到函数，请运行 [update-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-configuration.html) AWS CLI 命令。对于 `--layers` 参数，使用层 ARN。ARN 必须指定版本（例如 `arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1`）。有关更多信息，请参阅 [层和层版本](chapter-layers.md#lambda-layer-versions)。

```
aws lambda update-function-configuration --function-name my-function --cli-binary-format raw-in-base64-out --layers "arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1"
```

如果使用 **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)。

------
#### [ Console ]

**向函数添加层**

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

1. 选择函数。

1. 向下滚动到**层**部分，然后选择**添加层**。

1. 在**选择层**下，选择**自定义层**，然后选择您的层。
**注意**  
如果您在创建层时没有添加[兼容的运行时](https://docs.aws.amazon.com/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)，则您的层将不会在此处列出。您可以改为指定层 ARN。

1. 选择**添加**。

------

## 示例应用程序
<a name="python-layer-sample-app"></a>

有关如何使用 Lambda 层的更多示例，请参阅 AWS Lambda Developer Guide GitHub 存储库中的 [layer-python](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-python) 示例应用程序。此应用程序包括两个包含 Python 库的层。创建层后，即可部署并调用相应的函数来确认层是否按预期运行。

# 使用 Lambda 上下文对象检索 Python 函数信息
<a name="python-context"></a>

当 Lambda 运行您的函数时，它会将上下文对象传递到[处理程序](python-handler.md)。此对象提供的方法和属性包含有关调用、函数和执行环境的信息。有关如何将上下文对象传递到函数处理程序的更多信息，请参阅[定义采用 Python 的 Lambda 函数处理程序](python-handler.md)。

**上下文方法**
+ `get_remaining_time_in_millis` – 返回执行超时前剩余的毫秒数。

**上下文属性**
+ `function_name` – Lambda 函数的名称。
+ `function_version` – 函数的[版本](configuration-versions.md)
+ `invoked_function_arn` – 用于调用函数的 Amazon Resource Name (ARN)。表明调用者是否指定了版本号或别名。
+ `memory_limit_in_mb` – 为函数分配的内存量。
+ `aws_request_id` – 调用请求的标识符。
+ `log_group_name` – 函数的日志组。
+ `log_stream_name` – 函数实例的日志流。
+ `identity` –（移动应用程序）有关授权请求的 Amazon Cognito 身份的信息。
  + `cognito_identity_id` – 经过身份验证的 Amazon Cognito 身份。
  + `cognito_identity_pool_id` – 授权调用的 Amazon Cognito 身份池。
+ `client_context` – （移动应用程序）客户端应用程序提供给 Lambda 的客户端上下文。
  + `client.installation_id`
  + `client.app_title`
  + `client.app_version_name`
  + `client.app_version_code`
  + `client.app_package_name`
  + `custom` – 由移动客户端应用程序设置的自定义值的 `dict`。
  + `env` – 由AWS开发工具包提供的环境信息的 `dict`。

适用于 Lambda 的 Powertools（Python）为 Lambda 上下文对象提供了接口定义。接口定义可用于类型提示，也可以用于进一步检查 Lambda 上下文对象的结构。有关接口定义，请参阅 GitHub 上 *powertools-lambda-python* 存储库[中的 lambda\$1context.py](https://github.com/aws-powertools/powertools-lambda-python/blob/develop/aws_lambda_powertools/utilities/typing/lambda_context.py)。

以下示例显示记录上下文信息的处理程序函数。

**Example handler.py**  

```
import time

def lambda_handler(event, context):   
    print("Lambda function ARN:", context.invoked_function_arn)
    print("CloudWatch log stream name:", context.log_stream_name)
    print("CloudWatch log group name:",  context.log_group_name)
    print("Lambda Request ID:", context.aws_request_id)
    print("Lambda function memory limits in MB:", context.memory_limit_in_mb)
    # We have added a 1 second delay so you can see the time remaining in get_remaining_time_in_millis.
    time.sleep(1) 
    print("Lambda time remaining in MS:", context.get_remaining_time_in_millis())
```

除了上面列出的选项，您还可以使用适用于 AWS 的 [在 AWS Lambda 中检测 Python 代码](python-tracing.md) X-Ray 开发工具包来识别关键代码路径、跟踪其性能并收集数据以用于分析。

# Python Lambda 函数日志记录和监控
<a name="python-logging"></a>

AWS Lambda 将自动监控 Lambda 函数并将日志条目发送到 Amazon CloudWatch。您的 Lambda 函数带有一个 CloudWatch Logs 日志组以及函数的每个实例的日志流。Lambda 运行时系统环境会将每次调用的详细信息以及函数代码的其他输出发送到该日志流。有关 CloudWatch Logs 的更多信息，请参阅[将 Lambda 函数日志发送到 CloudWatch Logs](monitoring-cloudwatchlogs.md)。

要从函数代码输出日志，可以使用内置的 [https://docs.python.org/3/library/logging.html](https://docs.python.org/3/library/logging.html) 模块。如需更详细的条目，可以使用任何写入 `stdout` 或 `stderr` 的日志记录库。

## 输出到日志
<a name="python-logging-output"></a>

要将基本输出发送到日志，您可以使用函数中的 `print` 方法。以下示例记录了 CloudWatch Logs 日志组和流以及事件对象的值。

请注意，如果您的函数使用 Python `print` 语句输出日志，则 Lambda 只能以纯文本格式将日志输出发送到 CloudWatch Logs。要以结构化的 JSON 格式捕获日志，需要使用支持的日志记录库。请参阅[在 Python 中使用 Lambda 高级日志记录控件](#python-logging-advanced)了解更多信息。

**Example lambda\$1function.py**  

```
import os
def lambda_handler(event, context):
    print('## ENVIRONMENT VARIABLES')
    print(os.environ['AWS_LAMBDA_LOG_GROUP_NAME'])
    print(os.environ['AWS_LAMBDA_LOG_STREAM_NAME'])
    print('## EVENT')
    print(event)
```

**Example 日志输出**  

```
START RequestId: 8f507cfc-xmpl-4697-b07a-ac58fc914c95 Version: $LATEST
## ENVIRONMENT VARIABLES
/aws/lambda/my-function
2025/08/31/[$LATEST]3893xmpl7fac4485b47bb75b671a283c
## EVENT
{'key': 'value'}
END RequestId: 8f507cfc-xmpl-4697-b07a-ac58fc914c95
REPORT RequestId: 8f507cfc-xmpl-4697-b07a-ac58fc914c95  Duration: 15.74 ms  Billed Duration: 147 ms Memory Size: 128 MB Max Memory Used: 56 MB  Init Duration: 130.49 ms
XRAY TraceId: 1-5e34a614-10bdxmplf1fb44f07bc535a1   SegmentId: 07f5xmpl2d1f6f85 Sampled: true
```

Python 运行时记录每次调用的 `START`、`END` 和 `REPORT` 行。`REPORT` 行包括以下数据：

**REPORT 行数据字段**
+ **RequestId** – 调用的唯一请求 ID。
+ **Duration**（持续时间）– 函数的处理程序方法处理事件所花费的时间。
+ **Billed Duration**（计费持续时间）– 针对调用计费的时间量。
+ **Memory Size**（内存大小）– 分配给函数的内存量。
+ **Max Memory Used**（最大内存使用量）– 函数使用的内存量。如果调用共享执行环境，Lambda 会报告所有调用使用的最大内存。此行为可能会导致报告值高于预期。
+ **Init Duration**（初始持续时间）– 对于提供的第一个请求，为运行时在处理程序方法外部加载函数和运行代码所花费的时间。
+ **XRAY TraceId** – 对于追踪的请求，为 [AWS X-Ray 追踪 ID](services-xray.md)。
+ **SegmentId** – 对于追踪的请求，为 X-Ray 分段 ID。
+ **Sampled**（采样）– 对于追踪的请求，为采样结果。

## 使用日志记录库
<a name="python-logging-lib"></a>

如需更详细的日志，请使用标准库中的[日志记录](https://docs.python.org/3/library/logging.html)模块，或任何写入 `stdout` 或 `stderr` 的第三方日志记录库。

对于支持的 Python 运行时系统，您可以选择以纯文本还是 JSON 格式捕获使用标准 `logging` 模块创建的日志。要了解更多信息，请参阅[在 Python 中使用 Lambda 高级日志记录控件](#python-logging-advanced)。

目前，所有 Python 运行时的默认日志格式均为纯文本。以下示例显示了如何在 CloudWatch Logs 中以纯文本格式捕获使用标准 `logging` 模块创建的日志输出。

```
import os
import logging
logger = logging.getLogger()
logger.setLevel("INFO")
  
def lambda_handler(event, context):
    logger.info('## ENVIRONMENT VARIABLES')
    logger.info(os.environ['AWS_LAMBDA_LOG_GROUP_NAME'])
    logger.info(os.environ['AWS_LAMBDA_LOG_STREAM_NAME'])
    logger.info('## EVENT')
    logger.info(event)
```

`logger` 的输出包括日志级别、时间戳和请求 ID。

```
START RequestId: 1c8df7d3-xmpl-46da-9778-518e6eca8125 Version: $LATEST
[INFO]  2025-08-31T22:12:58.534Z    1c8df7d3-xmpl-46da-9778-518e6eca8125    ## ENVIRONMENT VARIABLES
[INFO]  2025-08-31T22:12:58.534Z    1c8df7d3-xmpl-46da-9778-518e6eca8125    /aws/lambda/my-function
[INFO]  2025-08-31T22:12:58.534Z    1c8df7d3-xmpl-46da-9778-518e6eca8125    2025/01/31/[$LATEST]1bbe51xmplb34a2788dbaa7433b0aa4d
[INFO]  2025-08-31T22:12:58.535Z    1c8df7d3-xmpl-46da-9778-518e6eca8125    ## EVENT
[INFO]  2025-08-31T22:12:58.535Z    1c8df7d3-xmpl-46da-9778-518e6eca8125    {'key': 'value'}
END RequestId: 1c8df7d3-xmpl-46da-9778-518e6eca8125
REPORT RequestId: 1c8df7d3-xmpl-46da-9778-518e6eca8125  Duration: 2.75 ms   Billed Duration: 117 ms Memory Size: 128 MB Max Memory Used: 56 MB  Init Duration: 113.51 ms
XRAY TraceId: 1-5e34a66a-474xmpl7c2534a87870b4370   SegmentId: 073cxmpl3e442861 Sampled: true
```

**注意**  
当函数的日志格式设置为纯文本时，Python 运行时系统的默认日志级别设置为 WARN。这意味着 Lambda 仅向 CloudWatch Logs 发送 WARN 及以下级别的日志输出。要更改默认日志级别，请使用 Python `logging` `setLevel()` 方法，如本示例代码所示。如果将函数的日志格式设置为 JSON，则建议使用 Lambda 高级日志记录控件来配置函数的日志级别，而不是通过在代码中设置日志级别。要了解更多信息，请参阅 [在 Python 中使用日志级别筛选](#python-logging-levels)。

## 在 Python 中使用 Lambda 高级日志记录控件
<a name="python-logging-advanced"></a>

为了让您更好地控制如何捕获、处理和使用函数日志，您可以为支持的 Lambda Python 运行时系统配置以下日志记录选项：
+ **日志格式** - 为函数日志选择纯文本或结构化的 JSON 格式
+ **日志级别** - 对于 JSON 格式的日志，选择 Lambda 发送到 Amazon CloudWatch 的日志的详细信息级别，例如 ERROR、DEBUG 或 INFO
+ **日志组** - 选择您的函数发送日志的目标 CloudWatch 日志组

有关这些日志记录选项的更多信息以及如何通过配置来使用函数的说明，请参阅 [为 Lambda 函数配置高级日志记录控件](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)。

要详细了解如何在 Python Lambda 函数中使用日志格式和日志级别选项，请参阅以下各节中的指南。

### 在 Python 中使用结构化的 JSON 日志
<a name="python-logging-JSON"></a>

如果您为函数的日志格式选择 JSON，Lambda 会将 Python 标准日志记录库输出的日志作为结构化的 JSON 发送到 CloudWatch。每个 JSON 日志对象包含至少四个键值对和以下键：
+ `"timestamp"` - 生成日志消息的时间
+ `"level"` - 分配给消息的日志级别
+ `"message"` - 日志消息的内容
+ `"requestId"` - 函数调用的唯一请求 ID

Python `logging` 库还可以向此 JSON 对象添加其他键值对，例如 `"logger"`。

以下各节中的示例显示了当您将函数的日志格式配置为 JSON 时，如何在 CloudWatch Logs 中捕获使用 Python `logging` 库生成的日志输出。

请注意，如果您使用 `print` 方法生成基本日志输出（如 [输出到日志](#python-logging-output) 中所述），则即使您将函数的日志格式配置为 JSON，Lambda 也会将这些输出捕获为纯文本。

#### 使用 Python 日志记录库的标准 JSON 日志输出
<a name="python-logging-standard"></a>

以下示例代码段和日志输出显示了当函数的日志格式被设置为 JSON 时，如何在 CloudWatch Logs 中捕获使用 Python `logging` 库生成的标准日志输出。

**Example Python 日志记录代码**  

```
import logging  
logger = logging.getLogger()

def lambda_handler(event, context):
    logger.info("Inside the handler function")
```

**Example JSON 日志记录**  

```
{
    "timestamp":"2025-10-27T19:17:45.586Z",
    "level":"INFO",
    "message":"Inside the handler function",
    "logger": "root",
    "requestId":"79b4f56e-95b1-4643-9700-2807f4e68189"
}
```

#### 在 JSON 中记录额外的参数
<a name="python-logging-extra"></a>

当函数的日志格式设置为 JSON 时，通过使用 `extra` 关键字将 Python 词典传递到日志输出，您还可以使用标准 Python `logging` 库记录其他参数。

**Example Python 日志记录代码**  

```
import logging

def lambda_handler(event, context):
    logging.info(
        "extra parameters example", 
        extra={"a":"b", "b": [3]},
    )
```

**Example JSON 日志记录**  

```
{
  "timestamp": "2025-11-02T15:26:28Z",
  "level": "INFO",
  "message": "extra parameters example",
  "logger": "root",
  "requestId": "3dbd5759-65f6-45f8-8d7d-5bdc79a3bd01",
  "a": "b",
  "b": [
    3
  ]
}
```

#### 在 JSON 中记录异常
<a name="python-logging-exception"></a>

以下代码段显示了当您将日志格式配置为 JSON 时，如何在函数的日志输出中捕获 Python 异常。请注意，使用 `logging.exception` 生成的日志输出被分配了日志级别 ERROR。

**Example Python 日志记录代码**  

```
import logging

def lambda_handler(event, context):
    try:
        raise Exception("exception")
    except:
        logging.exception("msg")
```

**Example JSON 日志记录**  

```
{
  "timestamp": "2025-11-02T16:18:57Z",
  "level": "ERROR",
  "message": "msg",
  "logger": "root",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 15, in lambda_handler\n    raise Exception(\"exception\")\n"
  ],
  "errorType": "Exception",
  "errorMessage": "exception",
  "requestId": "3f9d155c-0f09-46b7-bdf1-e91dab220855",
  "location": "/var/task/lambda_function.py:lambda_handler:17"
}
```

#### 使用其他日志记录工具的 JSON 结构化日志
<a name="python-logging-thirdparty"></a>

如果您的代码已经使用其他日志记录库（例如 Powertools for AWS Lambda）来生成 JSON 结构化日志，则无需进行任何更改。AWS Lambda 不会对任何已采用 JSON 编码的日志进行双重编码。即使您将函数配置为使用 JSON 日志格式，您的日志输出也会以您定义的 JSON 结构显示在 CloudWatch 中。

以下示例显示了如何在 CloudWatch Logs 中捕获使用 Powertools for AWS Lambda 软件包生成的日志输出。无论您的函数的日志配置设置为 JSON 还是 TEXT，此日志输出的格式都相同。有关使用 Powertools for AWS Lambda 的更多信息，请参阅 [将 Powertools for AWS Lambda（Python）和 AWS SAM 用于结构化日志记录](#python-logging-sam) 和 [将 Powertools for AWS Lambda（Python）和 AWS CDK 用于结构化日志记录](#python-logging-powertools-cdk)

**Example Python 日志记录代码段（使用 Powertools for AWS Lambda）**  

```
from aws_lambda_powertools import Logger

logger = Logger()

def lambda_handler(event, context):
    logger.info("Inside the handler function")
```

**Example JSON 日志记录（使用 Powertools for AWS Lambda）**  

```
{ 
    "level": "INFO", 
    "location": "lambda_handler:7", 
    "message": "Inside the handler function", 
    "timestamp": "2025-10-31 22:38:21,010+0000", 
    "service": "service_undefined", 
    "xray_trace_id": "1-654181dc-65c15d6b0fecbdd1531ecb30" 
}
```

### 在 Python 中使用日志级别筛选
<a name="python-logging-levels"></a>

通过配置日志级别筛选，您可以选择仅将特定日志记录级别或更低级别的日志发送到 CloudWatch Logs。要了解如何为您的函数配置日志级别筛选，请参阅 [日志级别筛选](monitoring-cloudwatchlogs-log-level.md)。

为了让 AWS Lambda 根据日志级别筛选应用程序日志，您的函数必须使用 JSON 格式的日志。您可以通过两种方式实现这一点：
+ 使用标准 Python `logging` 库创建日志输出，并将您的函数配置为使用 JSON 日志格式。然后 AWS Lambda 会使用 [在 Python 中使用结构化的 JSON 日志](#python-logging-JSON) 中所述的 JSON 对象中的“级别”键值对筛选日志输出。要了解如何配置函数的日志格式，请参阅 [为 Lambda 函数配置高级日志记录控件](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)。
+ 使用其他日志记录库或方法在代码中创建 JSON 结构化日志，其中包含定义日志输出级别的“级别”键值对。例如，您可以使用 Powertools for AWS Lambda 通过代码生成 JSON 结构化日志输出。

  您也可以使用 print 语句输出包含日志级别标识符的 JSON 对象。以下 print 语句生成 JSON 格式的输出，其中日志级别设置为 INFO。如果您的函数的日志级别设置为 INFO、DEBUG 或 TRACE，则 AWS Lambda 会将 JSON 对象发送到 CloudWatch Logs。

  ```
  print('{"msg":"My log message", "level":"info"}')
  ```

要让 Lambda 筛选函数的日志，还必须在 JSON 日志输出中包含一个 `"timestamp"` 键值对。必须以有效的 [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) 时间戳格式指定时间。如果您未提供有效的时间戳，Lambda 将为日志分配 INFO 级别并为您添加时间戳。

## 在 Lambda 控制台中查看日志
<a name="python-logging-console"></a>

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

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

## 在 CloudWatch 控制台中查看日志
<a name="python-logging-cwconsole"></a>

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

**使用 CloudWatch 控制台查看日志**

1. 打开 CloudWatch 控制台的 [Log groups](https://console.aws.amazon.com/cloudwatch/home?#logs:)（日志组页面）。

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

1. 创建日志流。

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

## 使用 AWS CLI 查看日志
<a name="python-logging-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="python-logging-delete"></a>

删除函数时，日志组不会自动删除。要避免无限期存储日志，请删除日志组，或[配置一个保留期](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#SettingLogRetention)，在该保留期之后，日志将自动删除。

## 使用其他日志记录工具和库
<a name="python-tools-libraries"></a>

[Powertools for AWS Lambda（Python）](https://docs.aws.amazon.com/powertools/python/)是一个开发人员工具包，用于实施无服务器最佳实践并提高开发人员速度。[日志记录实用程序](https://docs.aws.amazon.com/powertools/python/latest/core/logger/)提供经优化的 Lambda 日志记录程序，其中包含有关所有函数的函数上下文的附加信息，输出结构为 JSON。请使用该实用程序执行以下操作：
+ 从 Lambda 上下文中捕获关键字段，冷启动并将日志记录输出结构化为 JSON
+ 根据指示记录 Lambda 调用事件（默认情况下禁用）
+ 通过日志采样仅针对一定百分比的调用输出所有日志（默认情况下禁用）
+ 在任何时间点将其他键附加到结构化日志
+ 使用自定义日志格式设置程序（自带格式设置程序），从而在与组织的日志记录 RFC 兼容的结构中输出日志

## 将 Powertools for AWS Lambda（Python）和 AWS SAM 用于结构化日志记录
<a name="python-logging-sam"></a>

请按照以下步骤使用 AWS SAM，通过集成的 [Powertools for Python](https://docs.aws.amazon.com/powertools/python/latest/) 模块来下载、构建和部署示例 Hello World Python 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 `hello world` 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Python 3.9
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS SAM 应用程序**

1. 使用 Hello World Python 模板初始化该应用程序。

   ```
   sam init --app-template hello-world-powertools-python --name sam-app --package-type Zip --runtime python3.9 --no-tracing
   ```

1. 构建应用程序。

   ```
   cd sam-app && sam build
   ```

1. 部署应用程序。

   ```
   sam deploy --guided
   ```

1. 按照屏幕上的提示操作。要在交互式体验中接受提供的默认选项，请按 `Enter`。
**注意**  
对于 **HelloWorldFunction 可能没有定义授权，确定执行此操作吗？**，确保输入 `y`。

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl GET <URL_FROM_PREVIOUS_STEP>
   ```

   如果成功，您将会看到如下响应：

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的日志，请运行 [sam logs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-logs.html)。有关更多信息，请参阅《AWS Serverless Application Model 开发人员指南》中的 [使用日志](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html)**。

   ```
   sam logs --stack-name sam-app
   ```

   该日志输出类似于以下示例：

   ```
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:50.371000 INIT_START Runtime Version: python:3.9.v16    Runtime Version ARN: arn:aws:lambda:us-east-1::runtime:07a48df201798d627f2b950f03bb227aab4a655a1d019c3296406f95937e2525
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.112000 START RequestId: d455cfc4-7704-46df-901b-2a5cce9405be Version: $LATEST
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.114000 {
     "level": "INFO",
     "location": "hello:23",
     "message": "Hello world API - HTTP 200",
     "timestamp": "2025-02-03 14:59:51,113+0000",
     "service": "PowertoolsHelloWorld",
     "cold_start": true,
     "function_name": "sam-app-HelloWorldFunction-YBg8yfYtOc9j",
     "function_memory_size": "128",
     "function_arn": "arn:aws:lambda:us-east-1:111122223333:function:sam-app-HelloWorldFunction-YBg8yfYtOc9j",
     "function_request_id": "d455cfc4-7704-46df-901b-2a5cce9405be",
     "correlation_id": "e73f8aef-5e07-436e-a30b-63e4b23f0047",
     "xray_trace_id": "1-63dd2166-434a12c22e1307ff2114f299"
   }
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.126000 {
     "_aws": {
       "Timestamp": 1675436391126,
       "CloudWatchMetrics": [
         {
           "Namespace": "Powertools",
           "Dimensions": [
             [
               "function_name",
               "service"
             ]
           ],
           "Metrics": [
             {
               "Name": "ColdStart",
               "Unit": "Count"
             }
           ]
         }
       ]
     },
     "function_name": "sam-app-HelloWorldFunction-YBg8yfYtOc9j",
     "service": "PowertoolsHelloWorld",
     "ColdStart": [
       1.0
     ]
   }
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.126000 {
     "_aws": {
       "Timestamp": 1675436391126,
       "CloudWatchMetrics": [
         {
           "Namespace": "Powertools",
           "Dimensions": [
             [
               "service"
             ]
           ],
           "Metrics": [
             {
               "Name": "HelloWorldInvocations",
               "Unit": "Count"
             }
           ]
         }
       ]
     },
     "service": "PowertoolsHelloWorld",
     "HelloWorldInvocations": [
       1.0
     ]
   }
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.128000 END RequestId: d455cfc4-7704-46df-901b-2a5cce9405be
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.128000 REPORT RequestId: d455cfc4-7704-46df-901b-2a5cce9405be    Duration: 16.33 ms    Billed Duration: 756 ms    Memory Size: 128 MB    Max Memory Used: 64 MB    Init Duration: 739.46 ms    
   XRAY TraceId: 1-63dd2166-434a12c22e1307ff2114f299    SegmentId: 3c5d18d735a1ced0    Sampled: true
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   sam delete
   ```

### 管理日志保留日期
<a name="python-log-retention"></a>

删除函数时，日志组不会自动删除。要避免无限期存储日志，请删除日志组，或配置一个保留期，在该保留期结束后，日志将自动删除。要设置日志保留日期，请将以下内容添加到您的 AWS SAM 模板中：

```
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      # Omitting other properties

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/lambda/${HelloWorldFunction}"
      RetentionInDays: 7
```

## 将 Powertools for AWS Lambda（Python）和 AWS CDK 用于结构化日志记录
<a name="python-logging-powertools-cdk"></a>

请按照以下步骤使用 AWS CDK，通过集成的 [Powertools for AWS Lambda（Python）](https://docs.aws.amazon.com/powertools/python/latest/)模块来下载、构建和部署示例 Hello World Python 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 hello world 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Python 3.9
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK 版本 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS CDK 应用程序**

1. 为您的新应用程序创建一个项目目录。

   ```
   mkdir hello-world
   cd hello-world
   ```

1. 初始化该应用程序。

   ```
   cdk init app --language python
   ```

1.  安装 Python 依赖项。

   ```
   pip install -r requirements.txt
   ```

1. 在根文件夹下创建目录 **lambda\$1function**。

   ```
   mkdir lambda_function
   cd lambda_function
   ```

1. 创建文件 **app.py** 并将以下代码添加到该文件中。这是适用于 Lambda 函数的代码。

   ```
   from aws_lambda_powertools.event_handler import APIGatewayRestResolver
   from aws_lambda_powertools.utilities.typing import LambdaContext
   from aws_lambda_powertools.logging import correlation_paths
   from aws_lambda_powertools import Logger
   from aws_lambda_powertools import Tracer
   from aws_lambda_powertools import Metrics
   from aws_lambda_powertools.metrics import MetricUnit
   
   app = APIGatewayRestResolver()
   tracer = Tracer()
   logger = Logger()
   metrics = Metrics(namespace="PowertoolsSample")
   
   @app.get("/hello")
   @tracer.capture_method
   def hello():
       # adding custom metrics
       # See: https://docs.aws.amazon.com/powertools/python/latest//latest/core/metrics/
       metrics.add_metric(name="HelloWorldInvocations", unit=MetricUnit.Count, value=1)
   
       # structured log
       # See: https://docs.aws.amazon.com/powertools/python/latest//latest/core/logger/
       logger.info("Hello world API - HTTP 200")
       return {"message": "hello world"}
   
   # Enrich logging with contextual information from Lambda
   @logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
   # Adding tracer
   # See: https://docs.aws.amazon.com/powertools/python/latest//latest/core/tracer/
   @tracer.capture_lambda_handler
   # ensures metrics are flushed upon request completion/failure and capturing ColdStart metric
   @metrics.log_metrics(capture_cold_start_metric=True)
   def lambda_handler(event: dict, context: LambdaContext) -> dict:
       return app.resolve(event, context)
   ```

1. 打开 **hello\$1world** 目录。您应该会看到一个名为 **hello\$1world\$1stack.py** 的文件。

   ```
   cd ..
   cd hello_world
   ```

1. 打开 **hello\$1world\$1stack.py**，然后将以下代码添加到该文件中。其中包含 [Lambda 构造函数](https://docs.aws.amazon.com/cdk/api/v1/python/aws_cdk.aws_lambda.html)，该构造函数可创建 Lambda 函数，为 Powertools 配置环境变量并将日志保留期设置为一周；还包含 [ApiGatewayv1 构造函数](https://docs.aws.amazon.com/cdk/api/v1/python/aws_cdk.aws_apigateway.html)，用于创建 REST API。

   ```
   from aws_cdk import (
       Stack,
       aws_apigateway as apigwv1,
       aws_lambda as lambda_,
       CfnOutput,
       Duration
   )
   from constructs import Construct
   
   class HelloWorldStack(Stack):
   
       def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
           super().__init__(scope, construct_id, **kwargs)
   
           # Powertools Lambda Layer
           powertools_layer = lambda_.LayerVersion.from_layer_version_arn(
               self,
               id="lambda-powertools",
               # Using AWS Lambda Powertools via Lambda Layer
               # This imports the Powertools layer which provides observability features for Lambda functions
               # For available versions, see: https://docs.aws.amazon.com/powertools/python/latest/#lambda-layer
           )
   
           function = lambda_.Function(self,
               'sample-app-lambda',
               runtime=lambda_.Runtime.PYTHON_3_9,
               layers=[powertools_layer],
               code = lambda_.Code.from_asset("./lambda_function/"),
               handler="app.lambda_handler",
               memory_size=128,
               timeout=Duration.seconds(3),
               architecture=lambda_.Architecture.X86_64,
               environment={
                   "POWERTOOLS_SERVICE_NAME": "PowertoolsHelloWorld",
                   "POWERTOOLS_METRICS_NAMESPACE": "PowertoolsSample",
                   "LOG_LEVEL": "INFO"
               }
           )
   
           apigw = apigwv1.RestApi(self, "PowertoolsAPI", deploy_options=apigwv1.StageOptions(stage_name="dev"))
   
           hello_api = apigw.root.add_resource("hello")
           hello_api.add_method("GET", apigwv1.LambdaIntegration(function, proxy=True))
   
           CfnOutput(self, "apiUrl", value=f"{apigw.url}hello")
   ```

1. 部署您的应用程序。

   ```
   cd ..
   cdk deploy
   ```

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name HelloWorldStack --query 'Stacks[0].Outputs[?OutputKey==`apiUrl`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl GET <URL_FROM_PREVIOUS_STEP>
   ```

   如果成功，您将会看到如下响应：

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的日志，请运行 [sam logs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-logs.html)。有关更多信息，请参阅《AWS Serverless Application Model 开发人员指南》中的 [使用日志](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html)**。

   ```
   sam logs --stack-name HelloWorldStack
   ```

   该日志输出类似于以下示例：

   ```
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:50.371000 INIT_START Runtime Version: python:3.9.v16    Runtime Version ARN: arn:aws:lambda:us-east-1::runtime:07a48df201798d627f2b950f03bb227aab4a655a1d019c3296406f95937e2525
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.112000 START RequestId: d455cfc4-7704-46df-901b-2a5cce9405be Version: $LATEST
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.114000 {
     "level": "INFO",
     "location": "hello:23",
       "message": "Hello world API - HTTP 200",
     "timestamp": "2025-02-03 14:59:51,113+0000",
     "service": "PowertoolsHelloWorld",
     "cold_start": true,
     "function_name": "sam-app-HelloWorldFunction-YBg8yfYtOc9j",
     "function_memory_size": "128",
     "function_arn": "arn:aws:lambda:us-east-1:111122223333:function:sam-app-HelloWorldFunction-YBg8yfYtOc9j",
     "function_request_id": "d455cfc4-7704-46df-901b-2a5cce9405be",
     "correlation_id": "e73f8aef-5e07-436e-a30b-63e4b23f0047",
     "xray_trace_id": "1-63dd2166-434a12c22e1307ff2114f299"
   }
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.126000 {
     "_aws": {
       "Timestamp": 1675436391126,
       "CloudWatchMetrics": [
         {
           "Namespace": "Powertools",
           "Dimensions": [
             [
               "function_name",
               "service"
             ]
           ],
           "Metrics": [
             {
               "Name": "ColdStart",
               "Unit": "Count"
             }
           ]
         }
       ]
     },
     "function_name": "sam-app-HelloWorldFunction-YBg8yfYtOc9j",
     "service": "PowertoolsHelloWorld",
     "ColdStart": [
       1.0
     ]
   }
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.126000 {
     "_aws": {
       "Timestamp": 1675436391126,
       "CloudWatchMetrics": [
         {
           "Namespace": "Powertools",
           "Dimensions": [
             [
               "service"
             ]
           ],
           "Metrics": [
             {
               "Name": "HelloWorldInvocations",
               "Unit": "Count"
             }
           ]
         }
       ]
     },
     "service": "PowertoolsHelloWorld",
     "HelloWorldInvocations": [
       1.0
     ]
   }
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.128000 END RequestId: d455cfc4-7704-46df-901b-2a5cce9405be
   2025/02/03/[$LATEST]ea9a64ec87294bf6bbc9026c05a01e04 2025-02-03T14:59:51.128000 REPORT RequestId: d455cfc4-7704-46df-901b-2a5cce9405be    Duration: 16.33 ms    Billed Duration: 756 ms    Memory Size: 128 MB    Max Memory Used: 64 MB    Init Duration: 739.46 ms    
   XRAY TraceId: 1-63dd2166-434a12c22e1307ff2114f299    SegmentId: 3c5d18d735a1ced0    Sampled: true
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   cdk destroy
   ```

# Python 中的 AWS Lambda 函数测试
<a name="python-testing"></a>

**注意**  
有关测试无服务器解决方案的技术和最佳实践的完整介绍，请参阅[测试函数](testing-guide.md)一章。

 测试无服务器函数使用传统的测试类型和技术，但您还必须考虑对无服务器应用程序进行整体测试。基于云的测试将为您的函数和无服务器应用程序的质量提供**最准确**的衡量。

 无服务器应用程序架构包括可通过 API 调用提供关键应用程序功能的托管服务。因此，您的开发周期应包括在函数与服务交互时验证功能的自动化测试。

 如果您不创建基于云的测试，则可能会由于本地环境和已部署环境之间的差异而遇到问题。在将代码提升到下一个部署环境（例如 QA、暂存或生产）之前，您的持续集成过程应针对在云端预置的一套资源运行测试。

 继续阅读本简短指南，了解无服务器应用程序的测试策略，或者访问[无服务器测试示例存储库](https://github.com/aws-samples/serverless-test-samples)，深入了解特定于您所选语言和运行时系统的实用示例。

 ![\[illustration showing the relationship between types of tests\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/test-type-illustration2.png) 

 对于无服务器测试，您仍需要编写*单元*、*集成*和*端到端*测试。
+ **单元测试** – 针对隔离代码块运行的测试。例如，验证业务逻辑以计算给定特定项目和目的地的配送费用。
+ **集成测试** – 涉及通常在云环境中交互的两个或更多组件或服务的测试。例如，验证函数是否会处理队列中的事件。
+ **端到端测试** – 验证整个应用程序行为的测试。例如，确保正确设置基础设施，并确保事件在服务之间按预期流动，以记录客户的订单。

## 测试无服务器应用程序
<a name="python-testing-techniques-for-serverless-applications"></a>

 您通常会使用多种方法来测试无服务器应用程序代码，包括在云端进行测试、使用 Mock 进行测试，以及偶尔使用仿真器进行测试。

### 在云端进行测试
<a name="python-testing-in-the-cloud"></a>

 在云端进行测试对于各个阶段的测试（包括单元测试、集成测试和端到端测试）而言都很有价值。您可以针对部署在云端并与基于云的服务进行交互的代码运行测试。这种方法可以**准确**衡量代码的质量。

 在云端调试 Lambda 函数的一种便捷方法是在控制台中使用测试事件。*测试事件*是函数的一个 JSON 输入。如果函数不需要输入，则事件可以是空 JSON 文档 `({})`。控制台为各种服务集成提供示例事件。在控制台中创建事件后，您可以将其与团队共享，以简化测试并保持一致性。

**注意**  
[在控制台中测试函数](testing-functions.md)是一种快速开始的方法，但自动化测试周期可确保应用程序质量和开发速度。

### 测试工具
<a name="python-testing-tools"></a>

 有一些工具和技术可以加速开发反馈循环。例如，[AWS SAM Accelerate](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/accelerate.html) 和 [AWS CDK 监视模式](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-deploy-watch)都减少了更新云环境所需的时间。

[Moto](https://pypi.org/project/moto/) 是一个用于 Mock 模拟 AWS 服务和资源的 Python 库，以便您无需修改或稍作修改，就能使用装饰器拦截和模拟响应，以此测试函数。

 [Powertools for AWS Lambda（Python）](https://docs.powertools.aws.dev/lambda-python/latest/utilities/validation/)的验证功可提供装饰器，以便您可以验证 Python 函数的输入事件和输出响应。

 有关更多信息，请阅读博文[使用 Python 对 Lambda 进行单元测试和 Mock 模拟 AWS 服务](https://aws.amazon.com/blogs/devops/unit-testing-aws-lambda-with-python-and-mock-aws-services/)。

 要减少云部署迭代所涉及的延迟，请参阅 [AWS Serverless Application Model（AWS SAM）Accelerate](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/using-sam-cli-sync.html)、[AWS 云开发工具包（AWS CDK）监视模式](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-deploy-watch)。这些工具会监控基础设施和代码的变更情况，再通过创建增量更新并将其自动部署到云环境中来响应这些变更。

 使用这些工具的示例可在 [Python 测试示例](https://github.com/aws-samples/serverless-test-samples/tree/main/python-test-samples)代码存储库中找到。

# 在 AWS Lambda 中检测 Python 代码
<a name="python-tracing"></a>

Lambda 与 AWS X-Ray 集成，以帮助您跟踪、调试和优化 Lambda 应用程序。您可以在某个请求遍历应用程序中的资源（其中可能包括 Lambda 函数和其他 AWS 服务）时，使用 X-Ray 跟踪该请求。

要将跟踪数据发送到 X-Ray，您可以使用以下三个开发工具包库之一：
+ [适用于 OpenTelemetry 的 AWS 发行版 (ADOT)](https://aws.amazon.com/otel) – 一种安全、可供生产、支持 AWS 的 OpenTelemetry (OTel) SDK 的分发版本。
+ [AWS X-Ray SDK for Python](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python.html) – 用于生成跟踪数据并将其发送到 X-Ray 的 SDK
+ [Powertools for AWS Lambda（Python）](https://docs.aws.amazon.com/powertools/python/latest/)– 一个开发人员工具包，用于实施无服务器最佳实践并提高开发人员速度。

每个开发工具包均提供了将遥测数据发送到 X-Ray 服务的方法。然后，您可以使用 X-Ray 查看、筛选和获得对应用程序性能指标的洞察，从而发现问题和优化机会。

**重要**  
X-Ray 和 Powertools for AWS Lambda SDK 是 AWS 提供的紧密集成的分析解决方案的一部分。ADOT Lambda Layers 是全行业通用的跟踪分析标准的一部分，该标准通常会收集更多数据，但可能不适用于所有使用案例。您可以使用任一解决方案在 X-Ray 中实现端到端跟踪。要了解有关如何在两者之间进行选择的更多信息，请参阅[在 AWS Distro for Open Telemetry 和 X-Ray 开发工具包之间进行选择](https://docs.aws.amazon.com/xray/latest/devguide/xray-instrumenting-your-app.html#xray-instrumenting-choosing)。

**Topics**
+ [将 Powertools for AWS Lambda（Python）和 AWS SAM 用于跟踪](#python-tracing-sam)
+ [将 Powertools for AWS Lambda（Python）和 AWS CDK 用于跟踪](#python-logging-cdk)
+ [使用 ADOT 分析您的 Python 函数](#python-adot)
+ [使用 X-Ray SDK 分析您的 Python 函数](#python-xray-sdk)
+ [使用 Lambda 控制台激活跟踪](#python-tracing-console)
+ [使用 Lambda API 激活跟踪](#python-tracing-api)
+ [使用 CloudFormation 激活跟踪](#python-tracing-cloudformation)
+ [解释 X-Ray 跟踪](#python-tracing-interpretation)
+ [在层中存储运行时依赖项 (X-Ray SDK)](#python-tracing-layers)

## 将 Powertools for AWS Lambda（Python）和 AWS SAM 用于跟踪
<a name="python-tracing-sam"></a>

请按照以下步骤使用 AWS SAM，通过集成的 [Powertools for AWS Lambda（Python）](https://docs.powertools.aws.dev/lambda-python)模块来下载、构建和部署示例 Hello World Python 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 hello world 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Python 3.11
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS SAM 应用程序**

1. 使用 Hello World Python 模板初始化该应用程序。

   ```
   sam init --app-template hello-world-powertools-python --name sam-app --package-type Zip --runtime python3.11 --no-tracing
   ```

1. 构建应用程序。

   ```
   cd sam-app && sam build
   ```

1. 部署应用程序。

   ```
   sam deploy --guided
   ```

1. 按照屏幕上的提示操作。要在交互式体验中接受提供的默认选项，请按 `Enter`。
**注意**  
对于 **HelloWorldFunction 可能没有定义授权，确定执行此操作吗？**，确保输入 `y`。

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl -X GET <URL_FROM_PREVIOUS_STEP>
   ```

   如果成功，您将会看到如下响应：

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的跟踪信息，请运行 [sam traces](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   该跟踪输出类似于以下示例：

   ```
   New XRay Service Graph
     Start time: 2023-02-03 14:59:50+00:00
     End time: 2023-02-03 14:59:50+00:00
     Reference Id: 0 - (Root) AWS::Lambda - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: [1]
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0.924
     Reference Id: 1 - AWS::Lambda::Function - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: []
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0.016
     Reference Id: 2 - client - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: [0]
      Summary_statistics:
        - total requests: 0
        - ok count(2XX): 0
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0
   
   XRay Event [revision 1] at (2023-02-03T14:59:50.204000) with id (1-63dd2166-434a12c22e1307ff2114f299) and duration (0.924s)
    - 0.924s - sam-app-HelloWorldFunction-YBg8yfYtOc9j [HTTP: 200]
    - 0.016s - sam-app-HelloWorldFunction-YBg8yfYtOc9j
      - 0.739s - Initialization
      - 0.016s - Invocation
        - 0.013s - ## lambda_handler
          - 0.000s - ## app.hello
      - 0.000s - Overhead
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   sam delete
   ```

X-Ray 无法跟踪对应用程序的所有请求。X-Ray 将应用采样算法确保跟踪有效，同时仍会提供所有请求的一个代表性样本。采样率是每秒 1 个请求和 5% 的其他请求。您无法为函数配置此 X-Ray 采样率。

## 将 Powertools for AWS Lambda（Python）和 AWS CDK 用于跟踪
<a name="python-logging-cdk"></a>

请按照以下步骤使用 AWS CDK，通过集成的 [Powertools for AWS Lambda（Python）](https://docs.powertools.aws.dev/lambda-python)模块来下载、构建和部署示例 Hello World Python 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 hello world 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Python 3.11
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK 版本 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS CDK 应用程序**

1. 为您的新应用程序创建一个项目目录。

   ```
   mkdir hello-world
   cd hello-world
   ```

1. 初始化该应用程序。

   ```
   cdk init app --language python
   ```

1.  安装 Python 依赖项。

   ```
   pip install -r requirements.txt
   ```

1. 在根文件夹下创建目录 **lambda\$1function**。

   ```
   mkdir lambda_function
   cd lambda_function
   ```

1. 创建文件 **app.py** 并将以下代码添加到该文件中。这是适用于 Lambda 函数的代码。

   ```
   from aws_lambda_powertools.event_handler import APIGatewayRestResolver
   from aws_lambda_powertools.utilities.typing import LambdaContext
   from aws_lambda_powertools.logging import correlation_paths
   from aws_lambda_powertools import Logger
   from aws_lambda_powertools import Tracer
   from aws_lambda_powertools import Metrics
   from aws_lambda_powertools.metrics import MetricUnit
   
   app = APIGatewayRestResolver()
   tracer = Tracer()
   logger = Logger()
   metrics = Metrics(namespace="PowertoolsSample")
   
   @app.get("/hello")
   @tracer.capture_method
   def hello():
       # adding custom metrics
       # See: https://docs.powertools.aws.dev/lambda-python/latest/core/metrics/
       metrics.add_metric(name="HelloWorldInvocations", unit=MetricUnit.Count, value=1)
   
       # structured log
       # See: https://docs.powertools.aws.dev/lambda-python/latest/core/logger/
       logger.info("Hello world API - HTTP 200")
       return {"message": "hello world"}
   
   # Enrich logging with contextual information from Lambda
   @logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
   # Adding tracer
   # See: https://docs.powertools.aws.dev/lambda-python/latest/core/tracer/
   @tracer.capture_lambda_handler
   # ensures metrics are flushed upon request completion/failure and capturing ColdStart metric
   @metrics.log_metrics(capture_cold_start_metric=True)
   def lambda_handler(event: dict, context: LambdaContext) -> dict:
       return app.resolve(event, context)
   ```

1. 打开 **hello\$1world** 目录。您应该会看到一个名为 **hello\$1world\$1stack.py** 的文件。

   ```
   cd ..
   cd hello_world
   ```

1. 打开 **hello\$1world\$1stack.py**，然后将以下代码添加到该文件中。其中包含 [Lambda 构造函数](https://docs.aws.amazon.com/cdk/api/v1/python/aws_cdk.aws_lambda.html)，该构造函数可创建 Lambda 函数，为 Powertools 配置环境变量并将日志保留期设置为一周；还包含 [ApiGatewayv1 构造函数](https://docs.aws.amazon.com/cdk/api/v1/python/aws_cdk.aws_apigateway.html)，用于创建 REST API。

   ```
   from aws_cdk import (
       Stack,
       aws_apigateway as apigwv1,
       aws_lambda as lambda_,
       CfnOutput,
       Duration
   )
   from constructs import Construct
   
   class HelloWorldStack(Stack):
   
       def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
           super().__init__(scope, construct_id, **kwargs)
   
           # Powertools Lambda Layer
           powertools_layer = lambda_.LayerVersion.from_layer_version_arn(
               self,
               id="lambda-powertools",
               # At the moment we wrote this example, the aws_lambda_python_alpha CDK constructor is in Alpha, o we use layer to make the example simpler
               # See https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_lambda_python_alpha/README.html
               # Check all Powertools layers versions here: https://docs.powertools.aws.dev/lambda-python/latest/#lambda-layer
               layer_version_arn=f"arn:aws:lambda:{self.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:21"
           )
   
           function = lambda_.Function(self,
               'sample-app-lambda',
               runtime=lambda_.Runtime.PYTHON_3_11,
               layers=[powertools_layer],
               code = lambda_.Code.from_asset("./lambda_function/"),
               handler="app.lambda_handler",
               memory_size=128,
               timeout=Duration.seconds(3),
               architecture=lambda_.Architecture.X86_64,
               environment={
                   "POWERTOOLS_SERVICE_NAME": "PowertoolsHelloWorld",
                   "POWERTOOLS_METRICS_NAMESPACE": "PowertoolsSample",
                   "LOG_LEVEL": "INFO"
               }
           )
   
           apigw = apigwv1.RestApi(self, "PowertoolsAPI", deploy_options=apigwv1.StageOptions(stage_name="dev"))
   
           hello_api = apigw.root.add_resource("hello")
           hello_api.add_method("GET", apigwv1.LambdaIntegration(function, proxy=True))
   
           CfnOutput(self, "apiUrl", value=f"{apigw.url}hello")
   ```

1. 部署您的应用程序。

   ```
   cd ..
   cdk deploy
   ```

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name HelloWorldStack --query 'Stacks[0].Outputs[?OutputKey==`apiUrl`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl -X GET <URL_FROM_PREVIOUS_STEP>
   ```

   如果成功，您将会看到如下响应：

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的跟踪信息，请运行 [sam traces](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   该跟踪输出类似于以下示例：

   ```
   New XRay Service Graph
     Start time: 2023-02-03 14:59:50+00:00
     End time: 2023-02-03 14:59:50+00:00
     Reference Id: 0 - (Root) AWS::Lambda - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: [1]
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0.924
     Reference Id: 1 - AWS::Lambda::Function - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: []
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0.016
     Reference Id: 2 - client - sam-app-HelloWorldFunction-YBg8yfYtOc9j - Edges: [0]
      Summary_statistics:
        - total requests: 0
        - ok count(2XX): 0
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0
   
   XRay Event [revision 1] at (2023-02-03T14:59:50.204000) with id (1-63dd2166-434a12c22e1307ff2114f299) and duration (0.924s)
    - 0.924s - sam-app-HelloWorldFunction-YBg8yfYtOc9j [HTTP: 200]
    - 0.016s - sam-app-HelloWorldFunction-YBg8yfYtOc9j
      - 0.739s - Initialization
      - 0.016s - Invocation
        - 0.013s - ## lambda_handler
          - 0.000s - ## app.hello
      - 0.000s - Overhead
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   cdk destroy
   ```

## 使用 ADOT 分析您的 Python 函数
<a name="python-adot"></a>

ADOT 提供完全托管式 Lambda [层](chapter-layers.md)，这些层使用 OTel SDK，将收集遥测数据所需的一切内容打包起来。通过使用此层，您可以在不必修改任何函数代码的情况下，对您的 Lambda 函数进行分析。您还可以将您的层配置为对 OTel 进行自定义初始化。有关更多信息，请参阅 ADOT 文档中的[适用于 Lambda 上的 ADOT 收集器的自定义配置](https://aws-otel.github.io/docs/getting-started/lambda#custom-configuration-for-the-adot-collector-on-lambda)。

对于 Python 运行时，可以添加 **AWS适用于 ADOT Python 的托管 Lambda 层**以自动分析您的函数。此层适用于 arm64 和 x86\$164 架构。有关如何添加此层的详细说明，请参阅 ADOT 文档中的[适用于 OpenTelemetry 的 AWS 发行版对于 Python 的 Lambda 支持](https://aws-otel.github.io/docs/getting-started/lambda/lambda-python)。

## 使用 X-Ray SDK 分析您的 Python 函数
<a name="python-xray-sdk"></a>

要记录有关您的 Lambda 函数对应用程序中的其他资源进行调用的详细信息，您还可以使用 AWS X-Ray SDK for Python。要获取开发工具包，请将 `aws-xray-sdk` 包添加到应用程序的依赖项中。

**Example [requirements.txt](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-python/function/requirements.txt)**  

```
jsonpickle==1.3
aws-xray-sdk==2.4.3
```

在函数代码中，可以通过使用 `aws_xray_sdk.core` 模块修补 `boto3` 库来分析 AWS SDK 客户端。

**Example [函数 – 跟踪 AWS SDK 客户端](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-python/function/lambda_function.py)**  

```
import boto3
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all

logger = logging.getLogger()
logger.setLevel(logging.INFO)
patch_all()

client = boto3.client('lambda')
client.get_account_settings()

def lambda_handler(event, context):
    logger.info('## ENVIRONMENT VARIABLES\r' + jsonpickle.encode(dict(**os.environ)))
  ...
```

在添加正确的依赖项并进行必要的代码更改后，请通过 Lambda 控制台或 API 激活函数配置中的跟踪。

## 使用 Lambda 控制台激活跟踪
<a name="python-tracing-console"></a>

要使用控制台切换 Lambda 函数的活动跟踪，请按照以下步骤操作：

**打开活跃跟踪**

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

1. 选择函数。

1. 选择 **Configuration**（配置），然后选择 **Monitoring and operations tools**（监控和操作工具）。

1. 在**其他监控工具**下，选择**编辑**。

1. 在 **CloudWatch 应用程序信号和 AWS X-Ray** 下，为 **Lambda 服务跟踪**选择**启用**。

1. 选择**保存**。

## 使用 Lambda API 激活跟踪
<a name="python-tracing-api"></a>

借助 AWS CLI 或 AWS SDK 在 Lambda 函数上配置跟踪，请使用以下 API 操作：
+ [UpdateFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateFunctionConfiguration.html)
+ [GetFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionConfiguration.html)
+ [CreateFunction](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html)

以下示例 AWS CLI 命令对名为 **my-function** 的函数启用活跃跟踪。

```
aws lambda update-function-configuration --function-name my-function \
--tracing-config Mode=Active
```

跟踪模式是发布函数版本时版本特定配置的一部分。您无法更改已发布版本上的跟踪模式。

## 使用 CloudFormation 激活跟踪
<a name="python-tracing-cloudformation"></a>

要对 CloudFormation 模板中的 `AWS::Lambda::Function` 资源激活跟踪，请使用 `TracingConfig` 属性。

**Example [function-inline.yml](https://github.com/awsdocs/aws-lambda-developer-guide/blob/master/templates/function-inline.yml) – 跟踪配置**  

```
Resources:
  function:
    Type: [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)
    Properties:
      TracingConfig:
        Mode: Active
      ...
```

对于 AWS Serverless Application Model (AWS SAM) `AWS::Serverless::Function` 资源，请使用 `Tracing` 属性。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/template.yml) – 跟踪配置**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      Tracing: Active
      ...
```

## 解释 X-Ray 跟踪
<a name="python-tracing-interpretation"></a>

您的函数需要权限才能将跟踪数据上载到 X-Ray。在 Lambda 控制台中激活跟踪后，Lambda 会将所需权限添加到函数的[执行角色](lambda-intro-execution-role.md)。如果没有，请将 [AWSXRayDaemonWriteAccess](https://console.aws.amazon.com/iam/home#/policies/arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess) 策略添加到执行角色。

在配置活跃跟踪后，您可以通过应用程序观察特定请求。[X-Ray 服务图](https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html#xray-concepts-servicegraph)将显示有关应用程序及其所有组件的信息。以下示例显示了具有两个函数的应用程序。主函数处理事件，有时会返回错误。位于顶部的第二个函数将处理第一个函数的日志组中显示的错误，并使用 AWS SDK 调用 X-Ray、Amazon Simple Storage Service (Amazon S3) 和 Amazon CloudWatch Logs。

![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/sample-errorprocessor-servicemap.png)


X-Ray 无法跟踪对应用程序的所有请求。X-Ray 将应用采样算法确保跟踪有效，同时仍会提供所有请求的一个代表性样本。采样率是每秒 1 个请求和 5% 的其他请求。您无法为函数配置此 X-Ray 采样率。

在 X-Ray 中，*跟踪*记录有关由一个或多个*服务*处理的请求的信息。Lambda 会每个跟踪记录 2 个分段，这些分段将在服务图上创建两个节点。下图突出显示了这两个节点：

![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/xray-servicemap-function.png)


位于左侧的第一个节点表示接收调用请求的 Lambda 服务。第二个节点表示特定的 Lambda 函数。以下示例显示了一个包含这 2 个分段的跟踪。两者都命名为 **my-function**，但其中一个函数具有 `AWS::Lambda` 源，另一个则具有 `AWS::Lambda::Function` 源。如果 `AWS::Lambda` 分段显示错误，则表示 Lambda 服务存在问题。如果 `AWS::Lambda::Function` 分段显示错误，则说明函数存在问题。

![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/V2_sandbox_images/my-function-2-v1.png)


此示例将展开 `AWS::Lambda::Function` 分段，以显示其三个子分段。

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

旧样式函数分段包含以下子分段：
+ **初始化** – 表示加载函数和运行[初始化代码](foundation-progmodel.md)所花费的时间。此子分段仅对由您的函数的每个实例处理的第一个事件显示。
+ **调用** – 表示执行处理程序代码花费的时间。
+ **开销** – 表示 Lambda 运行时为准备处理下一个事件而花费的时间。

新样式函数分段不包含 `Invocation` 子分段。而是将客户子分段直接附加到函数分段。有关新旧样式函数分段结构的更多信息，请参阅 [了解 X-Ray 跟踪](services-xray.md#services-xray-traces)。

您还可以分析 HTTP 客户端、记录 SQL 查询以及使用注释和元数据创建自定义子段。有关更多信息，请参阅 *AWS X-Ray 开发人员指南*中的 [AWS X-Ray SDK for Python](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python.html)。

**定价**  
作为 AWS 免费套餐的组成部分，您可以每月免费使用 X-Ray 跟踪，但不能超过一定限制。超出该阈值后，X-Ray 会对跟踪存储和检索进行收费。有关更多信息，请参阅 [AWS X-Ray 定价](https://aws.amazon.com/xray/pricing/)。

## 在层中存储运行时依赖项 (X-Ray SDK)
<a name="python-tracing-layers"></a>

如果您使用 X-Ray 开发工具包来分析AWS开发工具包客户端和您的函数代码，则您的部署程序包可能会变得相当大。为了避免每次更新函数代码时上载运行时依赖项，请将 X-Ray SDK 打包到 [Lambda 层](chapter-layers.md)中。

以下示例显示存储 AWS X-Ray SDK for Python 的 `AWS::Serverless::LayerVersion` 资源。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-python/template.yml) – 依赖项层**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      CodeUri: function/.
      Tracing: Active
      Layers:
        - !Ref libs
      ...
  libs:
    Type: [AWS::Serverless::LayerVersion](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-layerversion.html)
    Properties:
      LayerName: blank-python-lib
      Description: Dependencies for the blank-python sample app.
      ContentUri: package/.
      CompatibleRuntimes:
        - python3.11
```

使用此配置，仅在更改运行时依赖项时您才会更新库层。由于函数部署软件包仅包含您的代码，因此可以帮助缩短上传时间。

为依赖项创建层需要更改构建才能在部署之前生成层存档。有关工作示例，请参阅 [blank-python](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-python) 示例应用程序。