

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 遷移至 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 SDK 檢測](#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. 使用適用於 Python 的 AWS Distro for OpenTelemetry (ADOT) 自動檢測 – 如需適用於 Python 應用程式的自動檢測，請參閱[使用適用於 OpenTelemetry Python 自動檢測的 AWS Distro 追蹤和指標](https://aws-otel.github.io/docs/getting-started/python-sdk/auto-instr)。

   （選用） 您也可以 AWS 在使用 ADOT Python 自動檢測功能自動檢測應用程式時啟用 CloudWatch Application Signals，以監控目前的應用程式運作狀態，並根據業務目標追蹤長期應用程式效能。Application Signals 為您提供應用程式、服務和相依性的統一、以應用程式為中心的檢視，並協助您監控和分類應用程式運作狀態。

1. 使用 OpenTelemetry Python 零碼自動檢測 – 如需使用 OpenTelemetry Python 自動檢測，請參閱 [Python 零碼檢測](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 ]

**注意**  
X-Ray 遠端取樣目前無法針對 OpenTelemetry Python 進行設定。不過，目前可透過適用於 Python 的 ADOT Auto-Instrumentation 支援 X-Ray 遠端取樣。

在 OpenTelemetry 中，您需要初始化全域 `TracerProvider`。使用此 `TracerProvider`，您可以取得 [Tracer](https://opentelemetry.io/docs/concepts/signals/traces/#tracer)，用於在應用程式中任何位置產生範圍。建議您設定下列元件：
+ `OTLPSpanExporter` – 將追蹤匯出至 CloudWatch Agent/OpenTelemetry Collector 時需要
+  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 用戶端等程式庫。如需詳細資訊，請參閱[使用 AWS Distro for OpenTelemetry Python Auto-Instrument 追蹤 和 指標](https://aws-otel.github.io/docs/getting-started/python-sdk/auto-instr)。

適用於 Python 的 ADOT 自動檢測支援：
+ 透過 環境變數進行 X-Ray 遠端取樣 `export OTEL_TRACES_SAMPLER=xray`
+ X-Ray 追蹤內容傳播 （預設為啟用）
+ 資源偵測 (Amazon EC2、Amazon ECS 和 Amazon EKS 環境的資源偵測預設為啟用）
+ 預設會啟用所有支援的 OpenTelemetry 檢測的自動程式庫檢測。您可以透過`OTEL_PYTHON_DISABLED_INSTRUMENTATIONS `環境變數選擇性地停用 （預設為啟用）
+ 手動建立跨度

**從 X-Ray 服務外掛程式到 OpenTelemetry AWS 資源提供者**

X-Ray 開發套件提供外掛程式，您可以新增至 `xray_recorder`，以從 Amazon EC2、Amazon ECS 和 Elastic Beanstalk 等託管服務擷取平台特定資訊。它類似於 OpenTelemetry 中將資訊擷取為資源屬性的資源提供者。有多個資源提供者可用於不同的 AWS 平台。
+ 首先安裝 AWS 延伸套件， `pip install opentelemetry-sdk-extension-aws`
+ 設定所需的資源偵測器。下列範例示範如何在 OpenTelemetry SDK 中設定 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) 的檢測。OpenTelemetry 中沒有可用的 Bottle 檢測，仍然可以使用 [OpenTelemetry WSGI 檢測](https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/wsgi/wsgi.html)來追蹤應用程式。

針對下列程式碼範例，您需要下列相依性：

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

您必須先初始化 OpenTelemetry SDK 並註冊全域 TracerProvider，才能為您的應用程式架構新增檢測。如果沒有它，追蹤操作將是 `no-ops`。設定全域 之後`TracerProvider`，您就可以針對應用程式架構使用 檢測器。下列範例示範 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 SDK 檢測
<a name="aws-sdk-instrumentation-python"></a>

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

X-Ray Python SDK 透過修補程式`botocore`庫來追蹤 AWS SDK 用戶端請求。如需詳細資訊，請參閱[使用適用於 Python 的 X-Ray AWS SDK 追蹤 SDK 呼叫](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python-awssdkclients.html)。在您的應用程式中， `patch_all()`方法用於使用 或 程式庫，選擇性地檢測所有`boto3`程式庫`botocore`或修補程式`patch((['botocore']))`。任何選擇的方法都會檢測您應用程式中的所有 Boto3 用戶端，並為使用這些用戶端進行的任何呼叫產生子區段。

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

針對下列程式碼範例，您將需要下列相依性：

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

以程式設計方式使用 [OpenTelemetry Botocore 檢測](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 呼叫。如需詳細資訊，請參閱[使用適用於 Python 的 X-Ray 開發套件追蹤對下游 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
```

以程式設計方式使用 OpenTelemetry Requests Instrumentation 來檢測請求程式庫，為應用程式中提出的 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>

您可以在支援的程式庫、架構、應用程式伺服器和 JVM 下找到 OpenTelemetry Python 支援的程式庫檢測的完整清單。 [ JVMs ](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md)

或者，您可以搜尋 OpenTelemetry 登錄檔，了解 OpenTelemetry 是否支援檢測。請參閱 [登錄](https://opentelemetry.io/ecosystem/registry/)檔以開始搜尋。

## 手動建立追蹤資料
<a name="manual-trace-creation-python"></a>

您可以在 `xray_recorder` Python 應用程式中使用 建立客群和子客群。如需詳細資訊，請參閱[手動檢測 Python 程式碼](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-python-middleware.html#xray-sdk-python-middleware-manual)。您也可以手動將註釋和中繼資料新增至追蹤資料。

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

使用 `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 檢測程式碼。

使用適用於 X-Ray 的 OpenTelemetry，建議在 [Application Signals](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-application-signals.html) 關閉的情況下使用適用於 OpenTelemetry 的 AWS Lambda Layer。這會自動檢測您的函數，並產生函數調用的範圍和函數的任何下游請求。除了追蹤之外，如果您有興趣使用 Application Signals 來監控函數的運作狀態，請參閱在 [Lambda 上啟用應用程式](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Application-Signals-Enable-LambdaMain.html)。
+ 從適用於 [AWS OpenTelemetry ARN 的 Lambda Layer 尋找函數所需的 Lambda layer ARNs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Application-Signals-Enable-LambdaMain.html#Enable-Lambda-Layers)，並將其新增。
+ 為您的 函數設定下列環境變數。
  + `AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument` – 這會載入函數的自動檢測
  + `OTEL_AWS_APPLICATION_SIGNALS_ENABLED=false` – 這會停用 Application Signals 監控

**使用 Lambda 檢測手動建立跨度**

此外，您可以在函數內產生自訂跨度，以追蹤工作。您可以只使用 `opentelemetry-api`套件搭配 AWS Lambda Layer for 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
       }
   ```