

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

# 遷移至 OpenTelemetry .NET
<a name="introduction-dotnet"></a>

在 .NET 應用程式中使用 X-Ray 追蹤時，X-Ray .NET 開發套件會手動用於檢測。

本節提供 [使用 SDK 的手動檢測解決方案](#manual-instrumentation-dotnet)區段中的程式碼範例，用於從 X-Ray 手動檢測解決方案遷移至適用於 .NET 的 OpenTelemetry 手動檢測解決方案。或者，您可以從 X-Ray 手動檢測遷移到 OpenTelemetry 自動檢測解決方案到檢測 .NET 應用程式，而無需修改 [零程式碼自動檢測解決方案](#zero-code-instrumentation-dotnet)區段中的應用程式原始碼。

**Topics**
+ [零程式碼自動檢測解決方案](#zero-code-instrumentation-dotnet)
+ [使用 SDK 的手動檢測解決方案](#manual-instrumentation-dotnet)
+ [手動建立追蹤資料](#manual-trace-creation-dotnet)
+ [追蹤傳入的請求 (ASP.NET 和 ASP.NET 核心檢測）](#tracing-incoming-requests-dotnet)
+ [AWS SDK 檢測](#aws-sdk-instrumentation-dotnet)
+ [檢測傳出的 HTTP 呼叫](#http-instrumentation-dotnet)
+ [其他程式庫的檢測支援](#other-libraries-dotnet)
+ [Lambda 檢測](#lambda-instrumentation)

## 零程式碼自動檢測解決方案
<a name="zero-code-instrumentation-dotnet"></a>

OpenTelemetry 提供零程式碼自動檢測解決方案。這些解決方案會追蹤請求，而不需要變更您的應用程式程式碼。

**OpenTelemetry 型自動檢測選項**

1. 使用適用於 .NET 的 AWS Distro for OpenTelemetry (ADOT) 自動檢測 – 若要自動檢測 .NET 應用程式，請參閱[使用適用於 OpenTelemetry 的 AWS Distro .NET Auto-Instrumentation 追蹤和指標](https://aws-otel.github.io/docs/getting-started/dotnet-sdk/auto-instr)。

   （選用） AWS 使用 ADOT .NET 自動檢測在 上自動檢測應用程式時啟用 CloudWatch Application Signals，以：
   + 監控目前的應用程式運作狀態
   + 根據業務目標追蹤長期應用程式效能
   + 取得應用程式、服務和相依性的統一、以應用程式為中心的檢視
   + 監控和分類應用程式運作狀態

   如需詳細資訊，請參閱 [Application Signals](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Application-Monitoring-Sections.html)。

1. 使用 OpenTelemetry .Net 零碼自動檢測 – 若要使用 OpenTelemetry .Net 自動檢測，請參閱[使用 AWS Distro for OpenTelemetry .NET Auto-Instrumentation 追蹤和指標](https://aws-otel.github.io/docs/getting-started/dotnet-sdk/auto-instr)。

## 使用 SDK 的手動檢測解決方案
<a name="manual-instrumentation-dotnet"></a>

------
#### [ Tracing configuration with X-Ray SDK ]

對於 .NET Web 應用程式，X-Ray SDK 是在 `Web.config` 檔案的 appSettings 區段中設定。

範例 Web.config

```
<configuration>
  <appSettings>
    <add key="AWSXRayPlugins" value="EC2Plugin"/>
  </appSettings>
</configuration>
```

針對 .NET Core，`XRay`會使用名為 `appsettings.json`且具有最上層金鑰的檔案，然後建置組態物件來初始化 X-Ray 記錄器。

.NET 的範例 `appsettings.json`

```
{
  "XRay": {
    "AWSXRayPlugins": "EC2Plugin"
  }
}
```

.NET Core Program.cs 的範例 – 記錄器組態

```
using Amazon.XRay.Recorder.Core;
...
AWSXRayRecorder.InitializeInstance(configuration);
```

------
#### [ Tracing configuration with OpenTelemetry SDK ]

****

新增這些相依性：

```
dotnet add package OpenTelemetry
dotnet add package OpenTelemetry.Contrib.Extensions.AWSXRay
dotnet add package OpenTelemetry.Sampler.AWS --prerelease
dotnet add package OpenTelemetry.Resources.AWS
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
```

針對您的 .NET 應用程式，透過設定 Global TracerProvider 來設定 OpenTelemetry SDK。下列範例組態也會啟用 的檢測`ASP.NET Core`。若要檢測 `ASP.NET`，請參閱 [追蹤傳入的請求 (ASP.NET 和 ASP.NET 核心檢測）](#tracing-incoming-requests-dotnet)。若要搭配其他架構使用 OpenTelemetry，請參閱 [登錄](https://opentelemetry.io/ecosystem/registry/)檔以取得更多支援架構的程式庫。

建議您設定下列元件：
+ `An OTLP Exporter` – 將追蹤匯出至 CloudWatch Agent/OpenTelemetry Collector 時需要
+  AWS X-Ray 傳播器 – 將追蹤內容傳播至[AWS 與 X-Ray 整合的服務](https://docs.aws.amazon.com/xray/latest/devguide/xray-services.html)時需要
+  AWS X-Ray 遠端取樣器 – 如果您需要[使用 X-Ray 取樣規則來取樣請求](https://docs.aws.amazon.com/xray/latest/devguide/xray-console-sampling.html)，則為必要項目
+ `Resource Detectors` （例如，Amazon EC2 Resource Detector) - 偵測執行您應用程式的主機中繼資料

```
using OpenTelemetry;
using OpenTelemetry.Contrib.Extensions.AWSXRay.Trace;
using OpenTelemetry.Sampler.AWS;
using OpenTelemetry.Trace;
using OpenTelemetry.Resources;

var builder = WebApplication.CreateBuilder(args);

var serviceName = "MyServiceName";
var serviceVersion = "1.0.0";

var resourceBuilder = ResourceBuilder
    .CreateDefault()
    .AddService(serviceName: serviceName)
    .AddAWSEC2Detector();

builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource
        .AddAWSEC2Detector()
        .AddService(
            serviceName: serviceName,
            serviceVersion: serviceVersion))
    .WithTracing(tracing => tracing
        .AddSource(serviceName)
        .AddAspNetCoreInstrumentation()
        .AddOtlpExporter()
        .SetSampler(AWSXRayRemoteSampler.Builder(resourceBuilder.Build())
            .SetEndpoint("http://localhost:2000")
            .Build()));

Sdk.SetDefaultTextMapPropagator(new AWSXRayPropagator()); // configure  X-Ray propagator
```

若要將 OpenTelemetry 用於主控台應用程式，請在程式啟動時新增下列 OpenTelemetry 組態。

```
using OpenTelemetry;
using OpenTelemetry.Contrib.Extensions.AWSXRay.Trace;
using OpenTelemetry.Trace;
using OpenTelemetry.Resources;

var serviceName = "MyServiceName";

var resourceBuilder = ResourceBuilder
    .CreateDefault()
    .AddService(serviceName: serviceName)
    .AddAWSEC2Detector();

var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddSource(serviceName)
    .ConfigureResource(resource =>
        resource
            .AddAWSEC2Detector()
            .AddService(
                serviceName: serviceName,
                serviceVersion: serviceVersion
            )
        )
    .AddOtlpExporter() // default address localhost:4317
    .SetSampler(new TraceIdRatioBasedSampler(1.00))
    .Build();

Sdk.SetDefaultTextMapPropagator(new AWSXRayPropagator()); // configure  X-Ray propagator
```

------

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

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

使用 X-Ray SDK，需要 `BeginSegment`和 `BeginSubsegment`方法來手動建立 X-Ray 區段和子區段。

```
using Amazon.XRay.Recorder.Core;

AWSXRayRecorder.Instance.BeginSegment("segment name"); // generates `TraceId` for you
try
{
    // Do something here
    // can create custom subsegments
    AWSXRayRecorder.Instance.BeginSubsegment("subsegment name");
    try
    {
        DoSometing();
    }
    catch (Exception e)
    {
        AWSXRayRecorder.Instance.AddException(e);
    }
    finally
    {
        AWSXRayRecorder.Instance.EndSubsegment();
    }
}
catch (Exception e)
{
    AWSXRayRecorder.Instance.AddException(e);
}
finally
{
    AWSXRayRecorder.Instance.EndSegment();
}
```

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

在 .NET 中，您可以使用活動 API 建立自訂範圍，以監控檢測程式庫未擷取的內部活動效能。請注意，只有種類的伺服器會轉換為 X-Ray 區段，所有其他範圍則會轉換為 X-Ray 子區段。

您可以視需要建立任意數量的`ActivitySource`執行個體，但建議在整個應用程式/服務中只有一個執行個體。

```
using System.Diagnostics;

ActivitySource activitySource = new ActivitySource("ActivitySourceName", "ActivitySourceVersion");


...


using (var activity = activitySource.StartActivity("ActivityName", ActivityKind.Server)) // this will be translated to a X-Ray Segment
{
    // Do something here

    using (var internalActivity = activitySource.StartActivity("ActivityName", ActivityKind.Internal)) // this will be translated to an X-Ray Subsegment
    {
        // Do something here
    }
}
```

**使用 OpenTelemetry SDK 將註釋和中繼資料新增至追蹤**

您也可以在 活動上使用 `SetTag`方法，將自訂金鑰/值對做為屬性新增至您的範圍。請注意，根據預設，所有跨度屬性都會轉換為 X-Ray 原始資料中的中繼資料。若要確保屬性轉換為註釋而非中繼資料，您可以將該屬性的索引鍵新增至`aws.xray.annotations`屬性清單。

```
using (var activity = activitySource.StartActivity("ActivityName", ActivityKind.Server)) // this will be translated to a X-Ray Segment
{
    activity.SetTag("metadataKey", "metadataValue");
    activity.SetTag("annotationKey", "annotationValue");
    string[] annotationKeys = {"annotationKey"};
    activity.SetTag("aws.xray.annotations", annotationKeys);

    // Do something here

    using (var internalActivity = activitySource.StartActivity("ActivityName", ActivityKind.Internal)) // this will be translated to an X-Ray Subsegment
    {
        // Do something here
    }
}
```

**使用 OpenTelemetry 自動檢測**

如果您使用適用於 .NET 的 OpenTelemetry 自動檢測解決方案，而且如果您需要在應用程式中執行手動檢測，例如，針對任何自動檢測程式庫未涵蓋的區段，在應用程式本身內檢測程式碼。

由於只能有一個全域 `TracerProvider`，`TracerProvider`如果與自動檢測一起使用，則手動檢測不應執行個體化自己的 。`TracerProvider` 使用 時，透過 OpenTelemetry SDK 使用自動檢測或手動檢測時，自訂手動追蹤的運作方式相同。

------

## 追蹤傳入的請求 (ASP.NET 和 ASP.NET 核心檢測）
<a name="tracing-incoming-requests-dotnet"></a>

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

若要檢測 ASP.NET 應用程式提供的請求，請參閱 以取得如何在 `global.asax` 檔案的 `Init`方法`RegisterXRay`中呼叫 [https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-messagehandler.html](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-messagehandler.html)的資訊。

```
AWSXRayASPNET.RegisterXRay(this, "MyApp");
```

若要檢測 ASP.NET 核心應用程式提供的請求，會在啟動類別`UseXRay`方法中的任何其他中介軟體之前呼叫 `Configure`方法。

```
app.UseXRay("MyApp");
```

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

OpenTelemetry 也提供檢測程式庫，以收集 ASP.NET 和 ASP.NET 核心傳入 Web 請求的追蹤。下一節列出為 OpenTelemetry 組態新增和啟用這些程式庫檢測所需的步驟，包括如何在建立 Tracer Provider 時新增 [ASP.NET](https://learn.microsoft.com/en-us/aspnet/overview) 或 [ASP.NET](https://learn.microsoft.com/en-us/aspnet/core/?view=aspnetcore-9.0) 核心檢測。

如需如何啟用 OpenTelemetry.Instrumentation.AspNet,請參閱[啟用 OpenTelemetry.Instrumentation.AspNet 的步驟](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Instrumentation.AspNet#steps-to-enable-opentelemetryinstrumentationaspnet)，以及有關如何啟用 OpenTelemetry.Instrumentation.AspNetCore,請參閱[啟用 OpenTelemetry.Instrumentation.AspNetCore 的步驟](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Instrumentation.AspNetCore#steps-to-enable-opentelemetryinstrumentationaspnetcore)。

------

## AWS SDK 檢測
<a name="aws-sdk-instrumentation-dotnet"></a>

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

呼叫 安裝所有 AWS SDK 用戶端`RegisterXRayForAllServices()`。

```
using Amazon.XRay.Recorder.Handlers.AwsSdk;
AWSSDKHandler.RegisterXRayForAllServices(); //place this before any instantiation of AmazonServiceClient
AmazonDynamoDBClient client = new AmazonDynamoDBClient(RegionEndpoint.USWest2); // AmazonDynamoDBClient is automatically registered with X-Ray
```

使用下列其中一種方法來進行特定 AWS 服務用戶端檢測。

```
AWSSDKHandler.RegisterXRay<IAmazonDynamoDB>(); // Registers specific type of AmazonServiceClient : All instances of IAmazonDynamoDB created after this line are registered
AWSSDKHandler.RegisterXRayManifest(String path); // To configure custom AWS Service Manifest file. This is optional, if you have followed "Configuration" section
```

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

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

```
dotnet add package OpenTelemetry.Instrumentation.AWS
```

若要檢測 AWS SDK，請更新設定 Global TracerProvider 的 OpenTelemetry SDK 組態。

```
builder.Services.AddOpenTelemetry()
    ...
    .WithTracing(tracing => tracing
        .AddAWSInstrumentation()
        ...
```

------

## 檢測傳出的 HTTP 呼叫
<a name="http-instrumentation-dotnet"></a>

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

X-Ray .NET SDK 透過擴充功能方法`GetResponseTraced()`或使用 `GetAsyncResponseTraced()`時`System.Net.HttpWebRequest`，或使用 `HttpClientXRayTracingHandler` 處理常式來追蹤傳出的 HTTP 呼叫`System.Net.Http.HttpClient`。

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

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

```
dotnet add package OpenTelemetry.Instrumentation.Http
```

若要檢測 `System.Net.Http.HttpClient`和 `System.Net.HttpWebRequest`，請更新設定 Global TracerProvider 的 OpenTelemetry SDK 組態。

```
builder.Services.AddOpenTelemetry()
    ...
    .WithTracing(tracing => tracing
        .AddHttpClientInstrumentation()
        ...
```

------

## 其他程式庫的檢測支援
<a name="other-libraries-dotnet"></a>

您可以搜尋和篩選 .NET 檢測程式庫的 OpenTelemetry 登錄檔，以了解 OpenTelemetry 是否支援您的程式庫檢測。請參閱 [登錄](https://opentelemetry.io/ecosystem/registry/)檔以開始搜尋。

## Lambda 檢測
<a name="lambda-instrumentation"></a>

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

使用 X-Ray 開發套件搭配 Lambda 需要下列程序：

1. 在 Lambda 函數上啟用*主動追蹤* 

1. Lambda 服務會建立代表處理常式調用的客群

1. 使用 X-Ray SDK 建立子區段或檢測程式庫

------
#### [ With OpenTelemetry-based solutions ]

您可以使用 AWS 付費的 Lambda 層自動檢測 Lambda。有兩種解決方案：
+ （建議） [AWS 適用於 OpenTelemetry 的 Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-application-signals.html)
+ 為了獲得更好的效能，建議您考慮使用 `OpenTelemetry Manual Instrumentation` 為 Lambda 函數產生 OpenTelemetry 追蹤。

------

**適用於 AWS Lambda 的 OpenTelemetry 手動檢測**

以下是 Lambda 函數程式碼 （不含檢測） 範例。

```
using System;
using System.Text;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;

// Assembly attribute to enable Lambda function logging
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace ExampleLambda;

public class ListBucketsHandler
{
    private static readonly AmazonS3Client s3Client = new();

    // new Lambda function handler passed in
    public async Task<string> HandleRequest(object input, ILambdaContext context)
    {
        try
        {
            var DoListBucketsAsyncResponse = await DoListBucketsAsync();
            context.Logger.LogInformation($"Results: {DoListBucketsAsyncResponse.Buckets}");

            context.Logger.LogInformation($"Successfully called ListBucketsAsync");
            return "Success!";
        }
        catch (Exception ex)
        {
            context.Logger.LogError($"Failed to call ListBucketsAsync: {ex.Message}");
            throw;
        }
    }

    private async Task<ListBucketsResponse> DoListBucketsAsync()
    {
        try
        {
            var putRequest = new ListBucketsRequest
            {
            };

            var response = await s3Client.ListBucketsAsync(putRequest);
            return response;
        }
        catch (AmazonS3Exception ex)
        {
            throw new Exception($"Failed to call ListBucketsAsync: {ex.Message}", ex);
        }
    }
}
```

若要手動檢測 Lambda 處理常式和 Amazon S3 用戶端，請執行下列動作。

1. 執行個體化 TracerProvider – 建議使用 `XrayUdpSpanExporter`、ParentBased Always On Sampler 和`Resource``service.name`設定為 Lambda 函數名稱的 來設定 TracerProvider。

1. 呼叫 將 SDK 用戶端檢測新增至 ，以使用 OpenTemetry AWS SDK 檢測來檢測 `AddAWSInstrumentation()` Amazon S3 AWS 用戶端 `TracerProvider`

1. 建立與原始 Lambda 函數具有相同簽章的包裝函式。呼叫 `AWSLambdaWrapper.Trace()` API 並傳遞 `TracerProvider`、原始 Lambda 函數及其輸入做為參數。將包裝函式設定為 Lambda 處理常式輸入。

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

```
dotnet add package OpenTelemetry.Instrumentation.AWSLambda
dotnet add package OpenTelemetry.Instrumentation.AWS
dotnet add package OpenTelemetry.Resources.AWS
dotnet add package AWS.Distro.OpenTelemetry.Exporter.Xray.Udp
```

下列程式碼示範必要的變更之後的 Lambda 函數。您可以建立額外的自訂範圍，以補充自動提供的範圍。

```
using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;
using OpenTelemetry;
using OpenTelemetry.Instrumentation.AWSLambda;
using OpenTelemetry.Trace;
using AWS.Distro.OpenTelemetry.Exporter.Xray.Udp;
using OpenTelemetry.Resources;

// Assembly attribute to enable Lambda function logging
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace ExampleLambda;

public class ListBucketsHandler
{
    private static readonly AmazonS3Client s3Client = new();

    TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder()
        .AddAWSLambdaConfigurations()
        .AddProcessor(
            new SimpleActivityExportProcessor(
                // AWS_LAMBDA_FUNCTION_NAME Environment Variable will be defined in AWS Lambda Environment
                new XrayUdpExporter(ResourceBuilder.CreateDefault().AddService(Environment.GetEnvironmentVariable("AWS_LAMBDA_FUNCTION_NAME")).Build())
            )
        )
        .AddAWSInstrumentation()
        .SetSampler(new ParentBasedSampler(new AlwaysOnSampler()))
        .Build();

    // new Lambda function handler passed in
    public async Task<string> HandleRequest(object input, ILambdaContext context)
    => await AWSLambdaWrapper.Trace(tracerProvider, OriginalHandleRequest, input, context);

    public async Task<string> OriginalHandleRequest(object input, ILambdaContext context)
    {
        try
        {
            var DoListBucketsAsyncResponse = await DoListBucketsAsync();
            context.Logger.LogInformation($"Results: {DoListBucketsAsyncResponse.Buckets}");

            context.Logger.LogInformation($"Successfully called ListBucketsAsync");
            return "Success!";
        }
        catch (Exception ex)
        {
            context.Logger.LogError($"Failed to call ListBucketsAsync: {ex.Message}");
            throw;
        }
    }

    private async Task<ListBucketsResponse> DoListBucketsAsync()
    {
        try
        {
            var putRequest = new ListBucketsRequest
            {
            };

            var response = await s3Client.ListBucketsAsync(putRequest);
            return response;
        }
        catch (AmazonS3Exception ex)
        {
            throw new Exception($"Failed to call ListBucketsAsync: {ex.Message}", ex);
        }
    }
}
```

叫用此 Lambda 時，您會在 CloudWatch 主控台的追蹤地圖中看到下列追蹤：

![\[適用於 .Net 的 CloudWatch 主控台中的追蹤映射\]](http://docs.aws.amazon.com/zh_tw/xray/latest/devguide/images/deprecation_dotnet.png)
