다음을 통해 공유


분산 추적 수집

이 문서의 적용 대상: ✔️ .NET Core 2.1 이상 버전 ✔️ .NET Framework 4.5 이상 버전

계측된 코드는 분산 추적의 일부로 Activity 개체를 만들 수 있지만, 나중에 전체 추적을 검토할 수 있도록 해당 개체의 정보를 중앙 스토리지에 수집해야 합니다. 이 자습서에서는 필요한 경우 애플리케이션 문제를 진단하는 데 사용할 수 있도록 다양한 방법으로 분산 추적 원격 분석을 수집합니다. 새 계측을 추가해야 하는 경우 계측 자습서를 참조하세요.

OpenTelemetry를 사용하여 추적 수집

OpenTelemetry는 클라우드 네이티브 소프트웨어에 관한 원격 분석 생성 및 수집의 표준화를 목표로 하는 Cloud Native Computing Foundation에서 지원하는 공급업체 중립 오픈 소스 프로젝트입니다. 이 예에서는 콘솔에서 분산 추적 정보를 수집하고 표시합니다. 정보를 다른 곳으로 보내도록 OpenTelemetry를 구성하는 방법을 알아보려면 OpenTelemetry 시작 가이드를 참조하세요.

ASP.NET 예

필수 조건

예제 애플리케이션 만들기

먼저 데모 애플리케이션으로 사용할 새 ASP.NET 웹앱을 만듭니다.

dotnet new webapp

이 앱은 웹 페이지를 표시하지만 웹 페이지를 탐색해도 분산 추적 정보는 아직 수집되지 않습니다.

컬렉션 구성

OpenTelemetry를 사용하려면 여러 NuGet 패키지에 대한 참조를 추가해야 합니다.

dotnet add package OpenTelemetry --version 1.4.0-rc1
dotnet add package OpenTelemetry.Exporter.Console --version 1.4.0-rc1
dotnet add package OpenTelemetry.Extensions.Hosting --version 1.4.0-rc1
dotnet add package OpenTelemetry.Instrumentation.AspNetCore --version 1.0.0-rc9.10

참고 항목

빌드 당시 1.4.0 릴리스 후보 1 빌드는 사용 가능한 OpenTelemetry의 최신 버전이었습니다. 최종 버전이 나오면 대신 사용합니다.

다음으로, 다음과 같이 Program.cs의 소스 코드를 수정합니다.

using OpenTelemetry;
using OpenTelemetry.Trace;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddOpenTelemetry()
    .WithTracing(builder =>
    {
        builder.AddAspNetCoreInstrumentation();
        builder.AddConsoleExporter();
    }).StartWithHost();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

앱을 실행하고 웹 브라우저를 사용하여 호스트되는 웹 페이지를 탐색합니다. 이제 OpenTelemetry 분산 추적을 사용하도록 설정했으므로 콘솔에 인쇄된 브라우저 웹 요청에 대한 정보를 볼 수 있습니다.

Activity.TraceId:            9c4519ce65a667280daedb3808d376f0
Activity.SpanId:             727c6a8a6cff664f
Activity.TraceFlags:         Recorded
Activity.ActivitySourceName: Microsoft.AspNetCore
Activity.DisplayName:        /
Activity.Kind:               Server
Activity.StartTime:          2023-01-08T01:56:05.4529879Z
Activity.Duration:           00:00:00.1048255
Activity.Tags:
    net.host.name: localhost
    net.host.port: 5163
    http.method: GET
    http.scheme: http
    http.target: /
    http.url: http://localhost:5163/
    http.flavor: 1.1
    http.user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76
    http.status_code: 200
Resource associated with Activity:
    service.name: unknown_service:demo

모든 OpenTelemetry 구성은 builder.Services.AddOpenTelemetry()로 시작하는 새 원본 줄에서 발생합니다. 분산 추적을 사용하도록 설정하기 위해 .WithTracing(...)을 사용했습니다. AddAspNetCoreInstrumentation()은 OpenTelemetry가 ASP.NET Core 웹 서버에서 생성된 모든 분산 추적 작업을 수집하도록 사용하도록 설정했으며, AddConsoleExporter()는 OpenTelemetry에 해당 정보를 콘솔에 보내도록 지시합니다. 앱이 비교적 간단하지 않은 경우 더 많은 계측 라이브러리를 추가하여 데이터베이스 쿼리 또는 아웃바운드 HTTP 요청에 대한 추적도 수집할 수 있습니다. 또한 콘솔 내보내기 도구를 Jaeger, Zipken 또는 사용하기로 선택한 다른 모니터링 서비스용 내보내기 도구로 바꿀 수도 있습니다.

콘솔 앱 예

필수 조건

예제 애플리케이션 만들기

분산 추적 원격 분석을 수집하려면 먼저 이를 생성해야 합니다. 일반적으로 이 계측은 라이브러리에 있지만, 간단히 설명하기 위해 StartActivity를 사용하여 몇 가지 예제 계측이 포함된 작은 앱을 만듭니다. 이 시점에는 수집이 이루어지지 않았으며 StartActivity()는 부작용이 없고 null을 반환합니다. 자세한 내용은 계측 자습서를 참조하세요.

dotnet new console

.NET 5 이상을 대상으로 하는 애플리케이션에는 이미 필요한 분산 추적 API가 포함되어 있습니다. 이전 .NET 버전을 대상으로 하는 앱의 경우 System.Diagnostics.DiagnosticSource NuGet 패키지 버전 5 이상을 추가합니다.

dotnet add package System.Diagnostics.DiagnosticSource

생성된 Program.cs의 콘텐츠를 다음 예제 소스로 바꿉니다.

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Sample.DistributedTracing
{
    class Program
    {
        static ActivitySource s_source = new ActivitySource("Sample.DistributedTracing");

        static async Task Main(string[] args)
        {
            await DoSomeWork();
            Console.WriteLine("Example work done");
        }

        static async Task DoSomeWork()
        {
            using (Activity a = s_source.StartActivity("SomeWork"))
            {
                await StepOne();
                await StepTwo();
            }
        }

        static async Task StepOne()
        {
            using (Activity a = s_source.StartActivity("StepOne"))
            {
                await Task.Delay(500);
            }
        }

        static async Task StepTwo()
        {
            using (Activity a = s_source.StartActivity("StepTwo"))
            {
                await Task.Delay(1000);
            }
        }
    }
}

앱을 실행해도 추적 데이터는 아직 수집되지 않습니다.

> dotnet run
Example work done

컬렉션 구성

OpenTelemetry.Exporter.Console NuGet 패키지를 추가합니다.

dotnet add package OpenTelemetry.Exporter.Console

추가 OpenTelemetry using 지시문을 사용하여 Program.cs를 업데이트합니다.

using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Diagnostics;
using System.Threading.Tasks;

Main()을 업데이트하여 OpenTelemetry TracerProvider를 만듭니다.

        public static async Task Main()
        {
            using var tracerProvider = Sdk.CreateTracerProviderBuilder()
                .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
                .AddSource("Sample.DistributedTracing")
                .AddConsoleExporter()
                .Build();

            await DoSomeWork();
            Console.WriteLine("Example work done");
        }

이제 앱은 분산 추적 정보를 수집하고 콘솔에 표시합니다.

> dotnet run
Activity.Id:          00-7759221f2c5599489d455b84fa0f90f4-6081a9b8041cd840-01
Activity.ParentId:    00-7759221f2c5599489d455b84fa0f90f4-9a52f72c08a9d447-01
Activity.DisplayName: StepOne
Activity.Kind:        Internal
Activity.StartTime:   2021-03-18T10:46:46.8649754Z
Activity.Duration:    00:00:00.5069226
Resource associated with Activity:
    service.name: MySample
    service.instance.id: 909a4624-3b2e-40e4-a86b-4a2c8003219e

Activity.Id:          00-7759221f2c5599489d455b84fa0f90f4-d2b283db91cf774c-01
Activity.ParentId:    00-7759221f2c5599489d455b84fa0f90f4-9a52f72c08a9d447-01
Activity.DisplayName: StepTwo
Activity.Kind:        Internal
Activity.StartTime:   2021-03-18T10:46:47.3838737Z
Activity.Duration:    00:00:01.0142278
Resource associated with Activity:
    service.name: MySample
    service.instance.id: 909a4624-3b2e-40e4-a86b-4a2c8003219e

Activity.Id:          00-7759221f2c5599489d455b84fa0f90f4-9a52f72c08a9d447-01
Activity.DisplayName: SomeWork
Activity.Kind:        Internal
Activity.StartTime:   2021-03-18T10:46:46.8634510Z
Activity.Duration:    00:00:01.5402045
Resource associated with Activity:
    service.name: MySample
    service.instance.id: 909a4624-3b2e-40e4-a86b-4a2c8003219e

Example work done
원본

예제 코드에서 OpenTelemetry가 코드에 이미 있던 ActivitySource에서 생성된 활동을 캡처하도록 AddSource("Sample.DistributedTracing")를 호출했습니다.

static ActivitySource s_source = new ActivitySource("Sample.DistributedTracing");

소스 이름으로 AddSource()를 호출하여 ActivitySource의 원격 분석을 캡처할 수 있습니다.

Exporters

콘솔 내보내기는 빠른 예제 또는 로컬 개발에 유용하지만 프로덕션 배포에서는 추적을 중앙 저장소로 보내는 것이 좋을 수 있습니다. OpenTelemetry는 여러 내보내기를 사용하여 다양한 대상을 지원합니다. OpenTelemetry 구성에 대한 자세한 내용은 OpenTelemetry getting started guide(OpenTelemetry 시작 가이드)를 참조하세요.

Application Insights를 사용하여 추적 수집

분산 추적 원격 분석은 ASP.NET 또는 ASP.NET Core 앱용 Application Insights SDK를 구성한 후 또는 코드리스 계측을 사용하도록 설정하면 자동으로 캡처됩니다.

자세한 내용은 Application Insights 분산 추적 설명서를 참조하세요.

참고 항목

현재 Application Insights는 잘 알려진 특정 활동 계측 수집만 지원하며 사용자가 추가한 새로운 활동은 무시합니다. Application Insights는 사용자 지정 분산 추적 정보를 추가하기 위한 공급업체별 API로 TrackDependency를 제공합니다.

사용자 지정 논리를 사용하여 추적 수집

개발자는 활동 추적 데이터에 관한 고유한 사용자 지정 컬렉션 논리를 자유롭게 만들 수 있습니다. 이 예제에서는 .NET에서 제공하는 System.Diagnostics.ActivityListener API를 사용하여 원격 분석을 수집하고 콘솔에 출력합니다.

필수 조건

예제 애플리케이션 만들기

먼저 일부 분산 추적 계측이 있지만 추적 데이터가 수집되지 않는 예제 애플리케이션을 만듭니다.

dotnet new console

.NET 5 이상을 대상으로 하는 애플리케이션에는 이미 필요한 분산 추적 API가 포함되어 있습니다. 이전 .NET 버전을 대상으로 하는 앱의 경우 System.Diagnostics.DiagnosticSource NuGet 패키지 버전 5 이상을 추가합니다.

dotnet add package System.Diagnostics.DiagnosticSource

생성된 Program.cs의 콘텐츠를 다음 예제 소스로 바꿉니다.

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Sample.DistributedTracing
{
    class Program
    {
        static ActivitySource s_source = new ActivitySource("Sample.DistributedTracing");

        static async Task Main(string[] args)
        {
            await DoSomeWork();
            Console.WriteLine("Example work done");
        }

        static async Task DoSomeWork()
        {
            using (Activity a = s_source.StartActivity("SomeWork"))
            {
                await StepOne();
                await StepTwo();
            }
        }

        static async Task StepOne()
        {
            using (Activity a = s_source.StartActivity("StepOne"))
            {
                await Task.Delay(500);
            }
        }

        static async Task StepTwo()
        {
            using (Activity a = s_source.StartActivity("StepTwo"))
            {
                await Task.Delay(1000);
            }
        }
    }
}

앱을 실행해도 추적 데이터는 아직 수집되지 않습니다.

> dotnet run
Example work done

추적을 수집하는 코드 추가

다음 코드를 사용하여 Main()을 업데이트합니다.

        static async Task Main(string[] args)
        {
            Activity.DefaultIdFormat = ActivityIdFormat.W3C;
            Activity.ForceDefaultIdFormat = true;

            Console.WriteLine("         {0,-15} {1,-60} {2,-15}", "OperationName", "Id", "Duration");
            ActivitySource.AddActivityListener(new ActivityListener()
            {
                ShouldListenTo = (source) => true,
                Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllDataAndRecorded,
                ActivityStarted = activity => Console.WriteLine("Started: {0,-15} {1,-60}", activity.OperationName, activity.Id),
                ActivityStopped = activity => Console.WriteLine("Stopped: {0,-15} {1,-60} {2,-15}", activity.OperationName, activity.Id, activity.Duration)
            });

            await DoSomeWork();
            Console.WriteLine("Example work done");
        }

이제 출력에 로깅이 포함됩니다.

> dotnet run
         OperationName   Id                                                           Duration
Started: SomeWork        00-bdb5faffc2fc1548b6ba49a31c4a0ae0-c447fb302059784f-01
Started: StepOne         00-bdb5faffc2fc1548b6ba49a31c4a0ae0-a7c77a4e9a02dc4a-01
Stopped: StepOne         00-bdb5faffc2fc1548b6ba49a31c4a0ae0-a7c77a4e9a02dc4a-01      00:00:00.5093849
Started: StepTwo         00-bdb5faffc2fc1548b6ba49a31c4a0ae0-9210ad536cae9e4e-01
Stopped: StepTwo         00-bdb5faffc2fc1548b6ba49a31c4a0ae0-9210ad536cae9e4e-01      00:00:01.0111847
Stopped: SomeWork        00-bdb5faffc2fc1548b6ba49a31c4a0ae0-c447fb302059784f-01      00:00:01.5236391
Example work done

DefaultIdFormatForceDefaultIdFormat을 설정하는 것은 선택 사항이지만 샘플이 다양한 .NET 런타임 버전에서 비슷한 출력을 생성하는 데 도움이 됩니다. .NET 5는 기본적으로 W3C TraceContext ID 형식을 사용하지만 이전 .NET 버전은 기본적으로 Hierarchical ID 형식을 사용합니다. 자세한 내용은 활동 ID를 참조하세요.

System.Diagnostics.ActivityListener는 활동 수명 동안 콜백을 수신하는 데 사용됩니다.

  • ShouldListenTo - 각 활동은 네임스페이스 및 생산자 역할을 하는 ActivitySource와 연결됩니다. 이 콜백은 프로세스의 각 ActivitySource에 대해 한 번 호출됩니다. 샘플링을 수행하려거나 이 소스에서 생성된 활동의 시작/중지 이벤트에 관한 알림을 받으려는 경우 true를 반환합니다.
  • Sample - 기본적으로 StartActivity는 일부 ActivityListener가 샘플링되어야 함을 나타내는 경우가 아니면 Activity 개체를 만들지 않습니다. AllDataAndRecorded를 반환하면 활동을 만들어야 하고, IsAllDataRequested를 true로 설정해야 하고, ActivityTraceFlags에서 Recorded 플래그를 설정해야 합니다. IsAllDataRequested는 수신기가 태그 및 이벤트와 같은 보조 활동 정보가 채워지는지 확인하려고 한다는 힌트로서 계측된 코드를 통해 관찰할 수 있습니다. Recorded 플래그는 W3C TraceContext ID에서 인코딩되며 이 추적을 샘플링해야 하는 분산 추적에 포함된 다른 프로세스에 대한 힌트입니다.
  • ActivityStartedActivityStopped는 각각 활동이 시작 및 중지될 때 호출됩니다. 이 콜백은 활동에 관한 관련 정보를 기록하거나 이 정보를 수정할 기회를 제공합니다. 활동이 방금 시작되었을 때 많은 데이터는 여전히 불완전할 수 있으며 활동이 중지되기 전에 채워집니다.

ActivityListener가 만들어지고 콜백이 채워지면 ActivitySource.AddActivityListener(ActivityListener)를 호출하면 콜백 호출이 시작됩니다. ActivityListener.Dispose()를 호출하여 콜백 흐름을 중지합니다. 다중 스레드 코드에서는 Dispose()가 실행 중이거나 반환된 직후에도 진행 중인 콜백 알림이 수신될 수 있습니다.