

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

# 迁移到 OpenTelemetry Python
<a name="migrate-xray-to-opentelemetry-python"></a>

本指南可帮助你将 Python 应用程序从 X-Ray SDK 迁移到 OpenTelemetry 仪器中。它涵盖了自动和手动检测方法，并提供了常见场景的代码示例。

**Topics**
+ [零代码自动检测解决方案](#zero-code-python)
+ [手动检测应用程序](#manual-instrumentation-python)
+ [跟踪设置初始化](#manual-instrumentation-python-tracing)
+ [跟踪传入请求](#tracing-incoming-requests-python)
+ [AWS 软件开发工具包工具](#aws-sdk-instrumentation-python)
+ [通过请求检测传出 HTTP 调用](#http-instrumentation-python)
+ [对其他库的检测支持](#xray-migration-libraries-python)
+ [手动创建跟踪数据](#manual-trace-creation-python)
+ [Lambda 检测](#lambda-instrumentation-python)

## 零代码自动检测解决方案
<a name="zero-code-python"></a>

使用 X-Ray SDK，您必须修改应用程序代码才能跟踪请求。 OpenTelemetry 提供用于跟踪请求的零代码自动检测解决方案。使用 OpenTelemetry，您可以选择使用零代码自动检测解决方案来跟踪请求。

**使用 OpenTelemetry基于自动仪器的零代码**

1. 将 AWS 发行版用于 Python 的 OpenTelemetry (ADOT) 自动插入 — 有关 Python 应用程序的自动检测，请参阅使用 Python 自动检测[AWS 发行版进行 OpenTelemetry 跟踪和衡量指标](https://aws-otel.github.io/docs/getting-started/python-sdk/auto-instr)。

   （可选）您还可以在使用 ADOT Python 自动检测应用程序时启用 CloudWatch 应用程序信号，以监控当前应用程序的运行状况并根据 AWS 业务目标跟踪长期应用程序性能。Application Signals 为您提供统一的、以应用程序为中心的应用程序、服务和依赖项视图，帮助您监控应用程序的运行状况并对其进行分类。

1. 使用 OpenTelemetry Python 零代码自动检测 — 要使用 Py OpenTelemetry thon 进行自动检测，请参阅 Pyt [hon 零代码](https://opentelemetry.io/docs/zero-code/python/)检测。

## 手动检测应用程序
<a name="manual-instrumentation-python"></a>

您可以使用 `pip` 命令手动检测应用程序。

------
#### [ With X-Ray SDK ]

```
pip install aws-xray-sdk
```

------
#### [ With OpenTelemetry SDK ]

```
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp opentelemetry-propagator-aws-xray
```

------

## 跟踪设置初始化
<a name="manual-instrumentation-python-tracing"></a>

------
#### [ With X-Ray SDK ]

在 X-Ray 中，系统会初始化全局 `xray_recorder` 并使用它来生成分段和子分段。

------
#### [ With OpenTelemetry SDK ]

**注意**  
目前无法为 OpenTelemetry Python 配置 X-Ray 远程采样。但是，目前可通过适用于 Python 的 ADOT 自动检测获取对 X-Ray 远程采样的支持。

在中 OpenTelemetry，你需要初始化一个全局变量`TracerProvider`。使用此 `TracerProvider`，您可以获得一个[跟踪器](https://opentelemetry.io/docs/concepts/signals/traces/#tracer)，用于在应用程序中的任何地方生成跨度。建议您配置以下组件：
+ `OTLPSpanExporter`— 将跟踪导出到 CloudWatch Agent/Collecto OpenTelemetry r 时需要此选项
+  AWS X-Ray 传播器 — 将跟踪上下文传播到与 X-Ray 集成的 AWS 服务所必需的

```
from opentelemetry import (
    trace,
    propagate
)
from opentelemetry.sdk.trace import TracerProvider

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.propagators.aws import AwsXRayPropagator

# Sends generated traces in the OTLP format to an OTel Collector running on port 4318
otlp_exporter = OTLPSpanExporter(endpoint="http://localhost:4318/v1/traces")
# Processes traces in batches as opposed to immediately one after the other
span_processor = BatchSpanProcessor(otlp_exporter)
# More configurations can be done here. We will visit them later.

# Sets the global default tracer provider
provider = TracerProvider(active_span_processor=span_processor)
trace.set_tracer_provider(provider)

# Configures the global propagator to use the X-Ray Propagator
propagate.set_global_textmap(AwsXRayPropagator())

# Creates a tracer from the global tracer provider
tracer = trace.get_tracer("my.tracer.name")
# Use this tracer to create Spans
```

------

**使用适用于 Python 的 ADOT 自动检测**

你可以使用适用于 Python 的 ADOT 自动插桩来自动为你的 Python OpenTelemetry 应用程序进行配置。通过使用 ADOT 自动检测，您无需手动更改代码即可跟踪传入的请求或跟踪 AWS SDK 或 HTTP 客户端等库。有关更多信息，请参阅使用适用于 [ OpenTelemetry Python 自动检测的 AWS 发行版进行跟踪和指标](https://aws-otel.github.io/docs/getting-started/python-sdk/auto-instr)。

适用于 Python 的 ADOT 自动检测支持：
+ 通过环境变量 `export OTEL_TRACES_SAMPLER=xray` 进行 X-Ray 远程采样
+ X-Ray 跟踪上下文传播（默认情况下启用）
+ 资源检测（Amazon EC2、Amazon ECS 和 Amazon EKS 环境的资源检测默认处于启用状态）
+ 默认情况下，所有支持的乐器的自动库 OpenTelemetry 乐器均处于启用状态。您可以通过 `OTEL_PYTHON_DISABLED_INSTRUMENTATIONS ` 环境变量有选择地禁用。（默认启用全部）
+ 手动创建跨度

**从 X-Ray 服务插件到 OpenTelemetry AWS 资源提供商**

X-Ray SDK 提供了插件，您可以将其添加到 `xray_recorder` 中，以从托管服务（例如 Amazon EC2、Amazon ECS 和 Elastic Beanstalk）捕获平台特定的信息。它类似于中的资源提供者 OpenTelemetry ，它将信息捕获为资源属性。有多个资源提供器可用于不同的 AWS 平台。
+ 首先安装 AWS 扩展包，`pip install opentelemetry-sdk-extension-aws`
+ 配置所需的资源检测器。以下示例显示了如何在 OpenTelemetry 软件开发工具包中配置 Amazon EC2 资源提供商

  ```
  from opentelemetry import trace
  from opentelemetry.sdk.trace import TracerProvider
  from opentelemetry.sdk.extension.aws.resource.ec2 import (
      AwsEc2ResourceDetector,
  )
  from opentelemetry.sdk.resources import get_aggregated_resources
  
  provider = TracerProvider(
      active_span_processor=span_processor,
      resource=get_aggregated_resources([
          AwsEc2ResourceDetector(),
      ]))
  
  trace.set_tracer_provider(provider)
  ```

## 跟踪传入请求
<a name="tracing-incoming-requests-python"></a>

------
#### [ With X-Ray SDK ]

X-Ray Python SDK 支持 Django、Flask 和 Bottle 等应用程序框架，来跟踪其上运行的 Python 应用程序的传入请求。这是通过为每个框架向应用程序添加 `XRayMiddleware` 来实现的。

------
#### [ With OpenTelemetry SDK ]

OpenTelemetry 通过特定的仪器库为 [Django](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/django/django.html) 和 [Flask](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/flask/flask.html) 提供工具。中没有适用于 Bottle 的工具 OpenTelemetry，仍然可以使用 [OpenTelemetry WSGI Instrumention 来跟踪应用程序。](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/wsgi/wsgi.html)

对于以下代码示例，您将需要以下依赖项：

```
pip install opentelemetry-instrumentation-flask
```

在为应用程序框架添加工具 TracerProvider 之前，必须初始化 OpenTelemetry SDK 并注册全局版本。没有它，跟踪操作将是 `no-ops`。配置全局 `TracerProvider` 后，即可将 Instrumentor 用于应用程序框架。以下示例展示了 Flask 应用程序。

```
from flask import Flask
from opentelemetry import trace
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.sdk.extension.aws.resource import AwsEc2ResourceDetector
from opentelemetry.sdk.resources import get_aggregated_resources
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter

provider = TracerProvider(resource=get_aggregated_resources(
    [
        AwsEc2ResourceDetector(),
    ]))

processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# Creates a tracer from the global tracer provider
tracer = trace.get_tracer("my.tracer.name")

app = Flask(__name__)

# Instrument the Flask app
FlaskInstrumentor().instrument_app(app)


@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    app.run()
```

------

## AWS 软件开发工具包工具
<a name="aws-sdk-instrumentation-python"></a>

------
#### [ With X-Ray SDK ]

X-Ray Python AWS SDK 通过修补`botocore`库来跟踪 SDK 客户端请求。有关更多信息，请参阅使用适用于 [Python 的 X-Ray SD AWS K 追踪 SDK 调用](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python-awssdkclients.html)。在应用程序中，`patch_all()` 方法用于检测所有库，或者使用 `botocore` 有选择地修补库或使用 `patch((['botocore']))` 修补 `boto3` 库。任何选定的方法都会对应用程序中的所有 Boto3 客户端进行检测，并为使用这些客户端进行的任何调用生成一个子段。

------
#### [ With OpenTelemetry SDK ]

对于以下代码示例，您将需要以下依赖项：

```
pip install opentelemetry-instrumentation-botocore
```

以编程方式使用 [OpenTelemetry Botocore Instrumenting 来检测](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/botocore/botocore.html)应用程序中的所有 Boto3 客户端。以下示例演示了 `botocore` 检测。

```
import boto3
import opentelemetry.trace as trace
from botocore.exceptions import ClientError
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.resources import get_aggregated_resources
from opentelemetry.sdk.trace.export import (
    BatchSpanProcessor,
    ConsoleSpanExporter,
)
from opentelemetry.instrumentation.botocore import BotocoreInstrumentor

provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# Creates a tracer from the global tracer provider
tracer = trace.get_tracer("my.tracer.name")

# Instrument BotoCore
BotocoreInstrumentor().instrument()

# Initialize S3 client
s3 = boto3.client("s3", region_name="us-east-1")

# Your bucket name
bucket_name = "my-example-bucket"

# Get bucket location (as an example of describing it)
try:
    response = s3.get_bucket_location(Bucket=bucket_name)
    region = response.get("LocationConstraint") or "us-east-1"
    print(f"Bucket '{bucket_name}' is in region: {region}")

    # Optionally, get bucket's creation date via list_buckets
    buckets = s3.list_buckets()
    for bucket in buckets["Buckets"]:
        if bucket["Name"] == bucket_name:
            print(f"Bucket created on: {bucket['CreationDate']}")
            break
except ClientError as e:
    print(f"Failed to describe bucket: {e}")
```

------

## 通过请求检测传出 HTTP 调用
<a name="http-instrumentation-python"></a>

------
#### [ With X-Ray SDK ]

X-Ray Python SDK 通过修补请求库来通过请求跟踪传出 HTTP 调用。有关更多信息，请参阅[使用 X-Ray SDK for Python 跟踪对下游 HTTP Web 服务的调用](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python-httpclients.html)。在应用程序中，您可以使用 `patch_all()` 方法来检测所有库，或者使用 `patch((['requests']))` 有选择地修补请求库。任何一个选项都会对 `requests` 库进行检测，为通过 `requests` 进行的任何调用生成一个子分段。

------
#### [ With OpenTelemetry SDK ]

对于以下代码示例，您将需要以下依赖项：

```
pip install opentelemetry-instrumentation-requests
```

以编程方式使用 Requests Instruction 来检测 OpenTelemetry 请求库，为其在应用程序中发出的 HTTP 请求生成跟踪。有关更多信息，请参阅[OpenTelemetry 请求检测](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/requests/requests.html)。以下示例演示了 `requests` 库检测。

```
from opentelemetry.instrumentation.requests import RequestsInstrumentor

# Instrument Requests
RequestsInstrumentor().instrument()

...

    example_session = requests.Session()
    example_session.get(url="https://example.com")
```

或者，您也可以对底层 `urllib3` 库进行检测以跟踪 HTTP 请求：

```
# pip install opentelemetry-instrumentation-urllib3
from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor

# Instrument urllib3
URLLib3Instrumentor().instrument()

...

    example_session = requests.Session()
    example_session.get(url="https://example.com")
```

------

## 对其他库的检测支持
<a name="xray-migration-libraries-python"></a>

你可以在支持的库[、框架、应用程序服务器和下找到支持 P OpenTelemetry ython 的库](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md)工具的完整列表。 JVMs

或者，您可以搜索 OpenTelemetry 注册表以了解是否 OpenTelemetry 支持检测。请查看[注册表](https://opentelemetry.io/ecosystem/registry/)开始搜索。

## 手动创建跟踪数据
<a name="manual-trace-creation-python"></a>

您可以在 Python 应用程序中使用 `xray_recorder` 创建分段和子分段。有关更多信息，请参阅[手动检测 Python 代码](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python-middleware.html#xray-sdk-python-middleware-manual)。您还可以手动将注释和元数据添加到跟踪数据。

**使用 SDK 创建跨度 OpenTelemetry **

使用 `start_as_current_span` API 启动跨度并将其设置为创建跨度。有关创建跨度的示例，请参阅[创建跨度](https://opentelemetry.io/docs/languages/python/instrumentation/#creating-spans)。跨度启动并处于当前作用域后，您可以通过添加属性、事件、异常、链接等向其添加更多信息。就像我们在 X-Ray 中使用分段和子分段一样，里面有不同类型的跨度。 OpenTelemetry只有 `SERVER` 类跨度会转换为 X-Ray 分段，而其他跨度会转换为 X-Ray 子分段。

```
from opentelemetry import trace
from opentelemetry.trace import SpanKind

import time

tracer = trace.get_tracer("my.tracer.name")

# Create a new span to track some work
with tracer.start_as_current_span("parent", kind=SpanKind.SERVER) as parent_span:
    time.sleep(1)

    # Create a nested span to track nested work
    with tracer.start_as_current_span("child", kind=SpanKind.CLIENT) as child_span:
        time.sleep(2)
        # the nested span is closed when it's out of scope

    # Now the parent span is the current span again
    time.sleep(1)

    # This span is also closed when it goes out of scope
```

**使用 OpenTelemetry SDK 向跟踪添加注释和元数据**

X-Ray Python SDK 提供了单独的 APIs、`put_annotation``put_metadata`用于向追踪添加注释和元数据的功能。在 OpenTelemetry SDK 中，注释和元数据只是通过 `set_attribute` API 添加的跨度上的属性。

您希望作为注释添加到跟踪中的跨度属性，这些属性会添加到预留键 `aws.xray.annotations` 下，该键的值是注释的键值对列表。所有其他跨度属性都将成为转换后的分段或子分段的元数据。

此外，如果您使用的是 ADOT 收集器，则可以通过在收集器配置中指定 `indexed_attributes`，来配置哪些跨度属性应转换为 X-Ray 注释。

以下示例演示了如何使用 OpenTelemetry SDK 向跟踪添加注释和元数据。

```
with tracer.start_as_current_span("parent", kind=SpanKind.SERVER) as parent_span:
    parent_span.set_attribute("TransactionId", "qwerty12345")
    parent_span.set_attribute("AccountId", "1234567890")

    # This will convert the TransactionId and AccountId to be searchable X-Ray annotations
    parent_span.set_attribute("aws.xray.annotations", ["TransactionId", "AccountId"])

    with tracer.start_as_current_span("child", kind=SpanKind.CLIENT) as child_span:

        # The MicroTransactionId will be converted to X-Ray metadata for the child subsegment
        child_span.set_attribute("MicroTransactionId", "micro12345")
```

## Lambda 检测
<a name="lambda-instrumentation-python"></a>

要在 X-Ray 上监控 lambda 函数，您可以启用 X-Ray 并向函数调用角色添加相应的权限。此外，如果您正在跟踪来自函数的下游请求，则需要使用 X-Ray Python SDK 来检测代码。

对 OpenTelemetry 于 X-Ray，建议在关闭[应用程序信号](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-application-signals.html)的情况下使用 AWS Lambda 层。 OpenTelemetry 这将自动检测您的函数，并将为函数调用和来自您函数的任何下游请求生成跨度。除了跟踪之外，如果您想要使用 Application Signals 来监控函数的运行状况，请参阅[在 Lambda 上启用应用程序](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Application-Signals-Enable-LambdaMain.html)。
+ 从 Lambda 层中找到您的函数所需的 Lambda 层 ARN 并将其[AWS 添](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Application-Signals-Enable-LambdaMain.html#Enable-Lambda-Layers)加。 OpenTelemetry ARNs
+ 为函数设置以下环境变量。
  + `AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument` – 这将加载函数的自动检测
  + `OTEL_AWS_APPLICATION_SIGNALS_ENABLED=false` – 这将禁用 Application Signals 监控

**使用 Lambda 检测手动创建跨度**

此外，您可以在函数中生成自定义跨度来跟踪工作。您可以通过仅将该`opentelemetry-api`包与 AWS Lambda 层结合使用来实现 OpenTelemetry 自动检测。

1. 将 `opentelemetry-api` 作为依赖项包含在函数中

1. 以下代码段是生成自定义跨度的示例

   ```
   from opentelemetry import trace
   
   # Get the tracer (auto‑configured by the AWS Lambda Layer for OpenTelemetry)
   tracer = trace.get_tracer(__name__)
   
   def handler(event, context):
       # This span is a child of the layer's root span
       with tracer.start_as_current_span("my-custom-span") as span:
           span.set_attribute("key1", "value1")
           span.add_event("custom-event", {"detail": "something happened"})
           
           # Any logic you want to trace
           result = some_internal_logic()
   
       return {
           "statusCode": 200,
           "body": result
       }
   ```