

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

# 迁移到 OpenTelemetry .NET
<a name="introduction-dotnet"></a>

在 .NET 应用程序中使用 X-Ray 跟踪功能时，需要采用 X-Ray .NET SDK 并进行手动配置才能进行检测。

本节在[使用 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 Core 检测）](#tracing-incoming-requests-dotnet)
+ [AWS 软件开发工具包工具](#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 的 OpenTelemetry (ADOT) 自动检测 AWS 发行版 — 要自动检测.NET 应用程序，请参阅使用适用于.NET 自动检测的[AWS 发行版进行跟踪和衡量指标](https://aws-otel.github.io/docs/getting-started/dotnet-sdk/auto-instr)。 OpenTelemetry 

   （可选）在 CloudWatch 使用 ADOT .NET 自动检测应用程序时启用应用程序信号， AWS 以：
   + 实时监控应用程序运行状况
   + 根据业务目标跟踪长期应用程序性能
   + 获得统一的、以应用程序为中心的应用程序、服务和依赖项视图
   + 监控应用程序运行状况并对其进行分类

   有关更多信息，请参阅 [Application Signals](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Application-Monitoring-Sections.html)。

1. 使用 OpenTelemetry .Net 零代码自动检测 — 要自动使用 OpenTelemetry .NET 进行检测，请参阅使用.NE [ OpenTelemetry T 自动检测 AWS 发行版进行跟踪和衡量指标](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，使用名为 `appsettings.json` 的文件，其顶层键名为 `XRay`，然后构建一个配置对象来初始化 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 来配置 OpenTelemetry SDK TracerProvider。以下示例配置还为 `ASP.NET Core` 启用了检测。要检测 `ASP.NET`，请参阅[跟踪传入请求（ASP.NET 和 ASP.NET Core 检测）](#tracing-incoming-requests-dotnet)。要与其他框架 OpenTelemetry 一起使用，请参阅[注册表](https://opentelemetry.io/ecosystem/registry/)，了解更多支持的框架的库。

建议您配置以下组件：
+ `An OTLP Exporter`— 将跟踪导出到 CloudWatch Agent/Collecto OpenTelemetry r 时需要此选项
+  AWS X-Ray 传播器 — 将跟踪上下文传播到与 X-Ray [集成的AWS 服务所必需的](https://docs.aws.amazon.com/xray/latest/devguide/xray-services.html)
+  AWS X-Ray-Remote 采样器 — 如果您需要[使用 X-Ray 采样规则对请求进行采样](https://docs.aws.amazon.com/xray/latest/devguide/xray-console-sampling.html)，则为必填项
+ `Resource Detectors`（例如 Amazon EC2 资源检测器）– 检测运行应用程序的主机的元数据

```
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 Core 检测）
<a name="tracing-incoming-requests-dotnet"></a>

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

要检测 ASP.NET 应用程序提供的请求，请参阅[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)，了解如何在 `global.asax` 文件的 `Init` 方法中调用 `RegisterXRay`。

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

要检测由 ASP.NET Core 应用程序提供的请求，需要在调用启动类 `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 .Instrumention 的信息。 AspNet，请参阅[启用 OpenTelemetry .Instrumention 的步骤。 AspNet](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Instrumentation.AspNet#steps-to-enable-opentelemetryinstrumentationaspnet)以及有关如何启用 OpenTelemetry .Instrumentation 的信息。 AspNetCore，请参阅[启用 OpenTelemetry .Instrumention 的步骤。 AspNetCore](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Instrumentation.AspNetCore#steps-to-enable-opentelemetryinstrumentationaspnetcore)。

------

## AWS 软件开发工具包工具
<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
```

要对 S AWS DK 进行检测，请更新设置全局 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 在使用 `System.Net.HttpWebRequest` 时通过扩展方法 `GetResponseTraced()` 或 `GetAsyncResponseTraced()` 跟踪传出 HTTP 调用，或者在使用 `System.Net.Http.HttpClient` 时通过 `HttpClientXRayTracingHandler` 处理程序跟踪传出 HTTP 调用。

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

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

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

要检测`System.Net.Http.HttpClient`和`System.Net.HttpWebRequest`，请更新设置全局 TracerProvider 的 OpenTelemetry SDK 配置。

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

------

## 对其他库的检测支持
<a name="other-libraries-dotnet"></a>

您可以在 OpenTelemetry 注册表中搜索和筛选.NET 工具库，以了解您的库是否 OpenTelemetry 支持插入。请查看[注册表](https://opentelemetry.io/ecosystem/registry/)开始搜索。

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

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

要将 X-Ray SDK 与 Lambda 结合使用，需要完成以下过程：

1. 在 Lambda 函数上启用*主动跟踪*。

1. Lambda 服务会创建一个表示处理程序调用的分段

1. 使用 X-Ray SDK 创建子分段或检测库

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

您可以使用已打开的 Lambda 图层自动检测您的 Lambda AWS 。有两种解决方案：
+ （推荐）适用于 [AWS Lambda 层 OpenTelemetry](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-application-signals.html)
+ 为了提高性能，您可能需要考虑使用`OpenTelemetry Manual Instrumentation`为您的 Lambda 函数生成 OpenTelemetry 跟踪。

------

**OpenTelemetry 针对 AWS Lambda 的手动检测**

以下是 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. 实例化 a TracerProvider — 建议配置 TracerProvider 为 Always On Sampler，`service.name`设置为 Lambda 函数名称。`XrayUdpSpanExporter` ParentBased `Resource`

1. 通过调用将 S OpenTemetry AWS DK 客户端插桩添加`AddAWSInstrumentation()`到 Amazon AWS S3 客户端 `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_cn/xray/latest/devguide/images/deprecation_dotnet.png)
