언어

.NET 분산 추적 구성

.NET 11 이상에서는 Microsoft.Extensions.Diagnostics.Tracing API를 사용하여 ActivityListener 인스턴스를 등록하고, 규칙을 사용하여 각 수신기가 받는 Activity 및 ActivitySource 인스턴스를 선택할 수 있습니다. 코드에서 규칙을 정의하거나 IConfiguration에서 로드합니다.

Important

추적 규칙은 이 추적 인프라를 통해 등록된 수신기에만 영향을 미칩니다. 원격 분석 내보내기가 만들고 관리하는 수신기를 포함하여 관련 없는 ActivityListener 인스턴스에는 영향을 주지 않습니다. 해당 리스너 또는 익스포터를 별도로 구성하세요.

레지스터 추적

API는 Microsoft.Extensions.Diagnostics 패키지에서 사용할 수 있습니다. Microsoft.AspNetCore.App 공유 프레임워크를 참조하는 앱에는 어셈블리가 이미 포함되어 있습니다.

IServiceCollection에서 AddTracing를 호출합니다. 콜백에서:

  • 각 리스너를 등록하려면 AddListener을 호출하십시오. 수신기 이름은 구성 규칙에서 수신기를 식별합니다.
  • ActivityListenerBuilder를 통해 수신기의 샘플링 및 알림 대리자를 구성합니다. 추적 인프라는 ShouldListenTo, 원본 구독 및 수신기 수명을 소유합니다.
  • 규칙을 포함하는 구성 섹션과 함께 AddConfiguration를 호출합니다. Tracing라는 이름의 섹션의 경우 configuration.GetSection("Tracing")을 전달합니다.

전체 샘플은 세 가지 호출을 모두 보여줍니다. .NET 호스트는 호스트가 시작될 때 추적 구독을 활성화합니다. 호스트 없이 종속성 주입을 사용하는 경우 등록된 ActivitySourceFactory를 확인하여 수신기를 구성하고 해당 구독을 활성화합니다. 전체 샘플은 팩터리를 직접 확인합니다.

추적 설정

구성 또는 코드를 통해 추적 규칙을 설정합니다. 리스너, 소스, 작업 및 범위와 일치하는 규칙이 없으면 해당 조합에 대해 추적이 비활성화된 상태로 유지됩니다.

코드 없이 추적 구성

구성을 사용하는 앱의 경우 섹션을 appsettings.json 또는 다른 Tracing에 추가합니다. 그런 다음, 해당 섹션을 AddConfiguration:

tracing.AddConfiguration(configuration.GetSection("Tracing"));

다음 예제에서는 지원되는 규칙 섹션 및 규칙 수준을 보여줍니다.

{
  "Tracing": {
    "EnabledTracing": {
      "Default": false,
      "Contoso": true,
      "Contoso.Orders": {
        "Default": true,
        "HealthCheck": false
      },
      "Contoso.*.Storage": true
    },
    "EnabledGlobalTracing": {
      "System.Net.Http": true
    },
    "EnabledLocalTracing": {
      "Contoso.Workers": true
    },
    "Console": {
      "EnabledLocalTracing": {
        "Contoso.Orders": {
          "Submit": false
        }
      }
    }
  }
}

EnabledGlobalTracing, EnabledLocalTracing 또는 EnabledTracing 섹션 바로 아래에 규칙을 추가합니다. 수준을 추가 Rules 하지 마세요.

규칙 섹션

원본 범위 및 규칙이 하나의 수신기를 대상으로 하는지 여부에 따라 규칙 섹션을 선택합니다.

섹션 일치하는 리스너 일치하는 활동 소스
EnabledTracing 등록된 모든 리스너 전역 및 로컬 소스.
EnabledGlobalTracing 등록된 모든 리스너 전역 소스만 해당
EnabledLocalTracing 등록된 모든 리스너 로컬 소스만.
{Listener}:EnabledTracing 이름이 지정된 리스너 전역 및 로컬 소스.
{Listener}:EnabledGlobalTracing 이름이 지정된 리스너 전역 소스에만 적용됩니다.
{Listener}:EnabledLocalTracing 명명된 리스너 로컬 소스만.

리스너 이름은 AddListener에 전달된 이름과 일치합니다. 섹션 이름 및 수신기 이름은 대/소문자를 구분하지 않습니다.

규칙 수준

모든 규칙 섹션에서 다음 키 양식 중 하나를 사용합니다.

키 형식 규칙 수준 Match
Default Default. 모든 원본 및 작동.
{SourceName} 활동 소스입니다. 일치하는 원본에서의 모든 작업입니다.
{SourceName}:Default 활동 소스. 일치하는 소스의 모든 작업입니다. 이 양식을 사용하면 소스에도 작업 규칙이 포함될 수 있습니다.
{SourceName}:{OperationName} 작동. 일치하는 소스의 이름이 지정된 작업입니다.

일치를 사용하거나 false 사용하지 않도록 설정하려면 true 각 리프 값을 설정합니다. 예를 들어, 앞의 구성:

  • 기본적으로 추적을 사용하지 않도록 설정합니다.
  • Contoso로 시작하는 이름의 소스를 사용하도록 설정합니다.
  • Contoso.Orders은 사용하도록 설정하지만 해당 HealthCheck 작업은 사용하지 않도록 설정합니다.
  • Contoso.로 시작하고 .Storage로 끝나는 소스 패턴을 사용하도록 설정합니다.
  • 전역 원본, 로컬 원본 또는 명명 Console된 수신기에만 적용되는 규칙을 추가합니다.

Default를 불리언 리프로 사용합니다. Default에 작업 하위 요소가 있으면, 구성은 Default을 리터럴 활동 소스 이름으로 처리합니다.

코드를 사용하여 추적 구성

AddTracing에 전달된 ITracingBuilder에서 EnableTracing 및 DisableTracing을 호출합니다.

tracing.EnableTracing(sourceName: "Contoso");
tracing.DisableTracing(
    sourceName: "Contoso.Orders",
    operationName: "HealthCheck");

해당 수준의 모든 값과 일치시키려면 sourceName, operationName 또는 listenerName를 생략하세요. 기본적으로 프로그래밍 방식 규칙은 전역 및 로컬 원본 모두에 적용됩니다. Local, Global 또는 둘 다를 scopes 인수로 전달하여 규칙의 범위를 좁힐 수 있습니다.

구성 규칙 및 프로그래매틱 규칙은 하나의 정렬된 규칙 집합을 형성합니다. 동일하게 구체적인 규칙이 충돌하는 경우 마지막에 추가된 규칙이 우선합니다. 따라서 EnableTracing, DisableTracing, AddConfiguration가 동일하게 구체적인 규칙을 추가할 때는 콜백의 AddTracing 호출 순서가 중요합니다.

활동 소스 이름 맞추기

원본 이름, 작업 이름 및 리스너 이름은 대/소문자를 구분하지 않는 ordinal 비교를 사용합니다. 소스 이름 규칙은 다음과 같은 일치 형식을 지원합니다.

  • 빈 원본 이름은 모든 원본과 일치합니다.
  • 와일드카드가 없는 원본 이름은 접두사 기준으로 일치합니다. 예를 들어 Contoso는 Contoso.Orders 및 ContosoPayments와 일치하며, matcher는 접두사 뒤에 구분 기호가 없어도 됩니다.
  • 와일드카드가 하나 * 있는 원본 이름은 접두사와 접미사가 있는 항목과 일치합니다. 예를 들어, Contoso.*.Storage은 Contoso.Orders.Storage과 일치하지만 Contoso.Orders.Api와는 일치하지 않습니다.
  • * 원본 이름은 모든 원본과 일치합니다.

작업 이름이 정확히 일치합니다. 접두사 또는 와일드카드 일치를 사용하지 않습니다.

규칙 우선순위 적용

각 수신기, 원본, 작업 및 범위 조합에 대해 추적 인프라는 일치하는 규칙 하나를 선택합니다. 일치 규칙을 다음 순서로 비교합니다.

  • 수신기별 규칙이 모든 수신기에 대한 규칙보다 우선합니다.
  • 원본 규칙이 기본 규칙보다 우선합니다. 두 소스 식이 일치하면 더 긴 식이 우선합니다. 비교는 * 와일드카드를 포함한 식 길이를 사용합니다.
  • 연산 규칙이 원본 수준 규칙보다 우선합니다.
  • 전역 전용 또는 로컬 전용 규칙이 두 범위를 모두 포함하는 규칙보다 우선합니다.
  • 앞의 모든 요소가 같으면 마지막 규칙이 우선합니다.

첫 번째 차이에서 비교가 중지됩니다. 예를 들어 리스너별 기본 규칙은 리스너 고유성이 먼저 평가되기 때문에 모든 리스너에 적용되는 소스별 규칙보다 우선 적용됩니다.

작업 규칙은 소스 구독도 제어합니다. 리스너는 작업 규칙에서 해당 소스의 하나 이상의 작업을 사용하도록 설정하는 경우 기본적으로 사용하지 않도록 설정된 소스를 구독합니다. 그런 다음 수신기는 None를 반환하고 비활성화된 작업에 대해 해당 콜백을 건너뜁니다.

전역 또는 로컬 활동 소스 선택

추적 인프라는 두 가지 활동 원본 범위를 구분합니다.

  • 전역 소스는 생성자를 통해 생성된 ActivitySource입니다. EnabledGlobalTracing 규칙은 이러한 소스에 적용됩니다.
  • 로컬 소스는 종속성 주입에서 확인된 ActivitySourceFactory에 의해 생성된 ActivitySource입니다. EnabledLocalTracing 규칙은 해당 팩터리에서 만든 소스에 적용됩니다.

종속성 주입 컨테이너가 원본 및 해당 추적 수신기를 관리하도록 하려는 경우에 사용합니다 Create . 팩터리의 리스너는 다른 팩터리에서 만든 로컬 원본을 무시합니다. 두 소스 형식 모두에 EnabledTracing 규칙이 적용됩니다.

이러한 범위는 AddTracing가 등록하는 수신기만 제한합니다. 독립 ActivityListener은 ShouldListenTo에서 만든 활동 원본에 대해서도 자체 ActivitySourceFactory 및 샘플링 콜백을 사용합니다.

추적 구성을 다시 로드

AddConfiguration 제공된 구성의 변경 토큰을 구독합니다. 구성 공급자가 다시 로드를 지원하고 변경 사항을 보고하는 경우 추적 인프라는 다음과 같이 동작합니다:

  • 규칙 집합을 다시 빌드합니다.
  • 등록된 각 리스너의 소스 구독을 새로 고칩니다.
  • 업데이트된 규칙을 후속 활동에 적용합니다.

앱은 다시 로드한 후에도 동일한 ActivitySource 인스턴스를 계속 사용할 수 있습니다. 후속 활동은 업데이트된 규칙을 사용합니다.

변경 내용을 자동으로 보고하지 않는 변경 가능한 공급자의 경우 구성을 업데이트하고 Reload를 호출합니다. 전체 샘플에서는 메모리 내 구성 공급자와 함께 이 방법을 사용합니다.

잘못된 구성 처리

추적 구성은 TryParse로 값을 구문 분석합니다. true와 false를 대소문자를 구분하지 않고 허용하며, 앞뒤 공백도 허용합니다. on, 1, 0, 또는 yes는 허용되지 않습니다.

구성 로더는 유효한 부울이 아닌 리프 값을 자동으로 무시합니다. 지원되는 스키마와 일치하지 않는 알 수 없거나 형식이 잘못된 섹션도 무시합니다. 이러한 경우 예외가 발생하지 않으므로 키 이름을 신중하게 확인하세요.

원본 식에는 최대 하나의 * 와일드카드가 포함될 수 있습니다. 둘 이상의 와일드카드가 있는 규칙은 앱을 시작하는 동안 또는 구성을 다시 로드한 후 규칙이 구체화될 때 ArgumentException 예외가 발생합니다. 프로그래매틱 규칙의 경우 None 또한 ArgumentOutOfRangeException을 발생시킵니다.

샘플 실행

다음 .NET 11 콘솔 앱은 활성화된 작업 하나와 사용하지 않도록 설정된 작업 하나를 만듭니다. 그런 다음, 비활성화된 작업의 규칙을 업데이트하고, Reload를 호출하고, 동일한 로컬 ActivitySource을 통해 작업을 다시 시작합니다.

using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.Tracing;

IConfigurationRoot configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["Tracing:EnabledTracing:Default"] = "false",
        ["Tracing:EnabledTracing:Contoso.Orders:Default"] = "true",
        ["Tracing:EnabledTracing:Contoso.Orders:DisabledOperation"] = "false",
    })
    .Build();

ServiceCollection services = new();
services.AddTracing(tracing =>
{
    tracing.AddListener("Console", listener =>
    {
        listener.Sample = static (ref ActivityCreationOptions<ActivityContext> _) =>
            ActivitySamplingResult.AllData;
        listener.SampleUsingParentId = static (ref ActivityCreationOptions<string> _) =>
            ActivitySamplingResult.AllData;
        listener.ActivityStarted = activity =>
            Console.WriteLine($"Listener started: {activity.OperationName}");
    });
    tracing.AddConfiguration(configuration.GetSection("Tracing"));
});

using ServiceProvider serviceProvider = services.BuildServiceProvider();
ActivitySourceFactory factory =
    serviceProvider.GetRequiredService<ActivitySourceFactory>();
using ActivitySource source = factory.Create("Contoso.Orders");

Console.WriteLine("Before reload:");
WriteResult(source, "EnabledOperation");
WriteResult(source, "DisabledOperation");

configuration["Tracing:EnabledTracing:Contoso.Orders:DisabledOperation"] = "true";
configuration.Reload();

Console.WriteLine("After reload:");
WriteResult(source, "DisabledOperation");

static void WriteResult(ActivitySource source, string operationName)
{
    using Activity? activity = source.StartActivity(operationName);
    string state = activity is null ? "disabled" : "enabled";
    Console.WriteLine($"{operationName}: {state}");
}
Imports System.Diagnostics
Imports Microsoft.Extensions.Configuration
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Diagnostics.Tracing

Module Program
    Sub Main()
        Dim initialData As New Dictionary(Of String, String) From {
            {"Tracing:EnabledTracing:Default", "false"},
            {"Tracing:EnabledTracing:Contoso.Orders:Default", "true"},
            {"Tracing:EnabledTracing:Contoso.Orders:DisabledOperation", "false"}
        }

        Dim configuration As IConfigurationRoot =
            New ConfigurationBuilder().AddInMemoryCollection(initialData).Build()

        Dim services As New ServiceCollection()
        services.AddTracing(
            Sub(tracing)
                tracing.AddListener(
                    "Console",
                    Sub(listener)
                        listener.Sample = AddressOf SampleActivity
                        listener.SampleUsingParentId = AddressOf SampleActivityUsingParentId
                        listener.ActivityStarted =
                            Sub(activity) Console.WriteLine(
                                $"Listener started: {activity.OperationName}")
                    End Sub)
                tracing.AddConfiguration(configuration.GetSection("Tracing"))
            End Sub)

        Using serviceProvider As ServiceProvider = services.BuildServiceProvider()
            Dim factory As ActivitySourceFactory =
                serviceProvider.GetRequiredService(Of ActivitySourceFactory)()

            Using source As ActivitySource = factory.Create("Contoso.Orders")
                Console.WriteLine("Before reload:")
                WriteResult(source, "EnabledOperation")
                WriteResult(source, "DisabledOperation")

                configuration(
                    "Tracing:EnabledTracing:Contoso.Orders:DisabledOperation") = "true"
                configuration.Reload()

                Console.WriteLine("After reload:")
                WriteResult(source, "DisabledOperation")
            End Using
        End Using
    End Sub

    Private Function SampleActivity(
        ByRef options As ActivityCreationOptions(Of ActivityContext)
    ) As ActivitySamplingResult
        Return ActivitySamplingResult.AllData
    End Function

    Private Function SampleActivityUsingParentId(
        ByRef options As ActivityCreationOptions(Of String)
    ) As ActivitySamplingResult
        Return ActivitySamplingResult.AllData
    End Function

    Private Sub WriteResult(source As ActivitySource, operationName As String)
        Using activity As Activity = source.StartActivity(operationName)
            Dim state As String = If(activity Is Nothing, "disabled", "enabled")
            Console.WriteLine($"{operationName}: {state}")
        End Using
    End Sub
End Module

C# 및 Visual Basic 샘플은 동일한 결과를 생성합니다.

Before reload:
Listener started: EnabledOperation
EnabledOperation: enabled
DisabledOperation: disabled
After reload:
Listener started: DisabledOperation
DisabledOperation: enabled

또한, 다음을 참조하세요.