다음을 통해 공유


OpenTelemetry를 사용한 .NET 가시성

애플리케이션을 실행할 때 앱이 잘 작동하고 있는지 확인하고 잠재적인 문제가 더 심각해지기 전에 이를 알아내고자 할 것입니다. 앱에서 로그나 메트릭과 같은 원격 분석 데이터를 내보낸 다음, 해당 데이터를 모니터링하고 분석하여 그렇게 할 수 있습니다.

가시성이란?

분산 시스템의 컨텍스트에서 가시성이란 각 구성 요소의 상태에 대한 원격 분석을 모니터링하고 분석하여 성능의 변화를 관찰하고 그러한 변화가 발생하는 이유를 진단하는 기능입니다. 디버깅은 침습적이고 애플리케이션 작동에 영향을 줄 수 있는 반면에, 가시성은 기본적인 작업에 투명하고 성능에 미치는 영향이 작아 지속적으로 사용할 수 있습니다.

가시성은 일반적으로 다음의 조합을 사용하여 수행됩니다.

  • 수신되는 요청, 특정 구성 요소의 오류 또는 진행 중인 주문과 같은 개별 작업을 기록하는 로그입니다.
  • 완료된 요청 수, 활성 요청 수, 판매된 위젯 수와 같은 카운터와 게이지 또는 요청 대기 시간의 히스토그램을 측정하는 메트릭입니다.
  • 시간이 어디에 소요되는지 확인하고 특정 오류를 추적할 수 있도록 분산 시스템의 구성 요소에서 요청과 활동을 추적하는 분산 추적입니다.

로그, 메트릭, 분산 추적을 함께 가시성의 세 가지 핵심 요소라고 합니다.

각 핵심 요소에는 다음의 원격 분석 데이터가 포함될 수 있습니다.

  • 가비지 수집기 또는 JIT 컴파일러와 같은 .NET 런타임입니다.
  • Kestrel(ASP.NET 웹 서버) 및 HttpClient와 같은 라이브러리입니다.
  • 코드에서 내보낸 애플리케이션별 원격 분석입니다.

.NET에서의 가시성 접근법

.NET 애플리케이션에서 가시성을 달성하는 방법에는 몇 가지가 있습니다.

  • OpenTelemetry와 같은 라이브러리를 참조하고 사용하여 코드에서 명시적으로 수행합니다. 소스 코드에 액세스할 수 있고 앱을 다시 빌드할 수 있는 경우 이는 가장 강력하고 구성 가능한 메커니즘입니다.
  • EventPipe를 사용하는Out of Process입니다. dotnet-monitor와 같은 도구는 로그와 메트릭을 수신 대기한 다음, 코드에 영향을 주지 않고 처리할 수 있습니다.
  • 시작 후크를 사용하여 어셈블리를 프로세스에 삽입한 다음, 계측을 수집할 수 있습니다. 이 방법의 예로 OpenTelemetry .NET 자동 계측이 있습니다.

OpenTelemetry란?

OpenTelemetry(OTel)는 원격 분석 데이터를 수집하고 내보내는 플랫폼 간 개방형 표준입니다. OpenTelemetry에는 다음이 포함됩니다.

  • 코드가 실행 중일 때 원격 분석 데이터를 기록하는 데 사용할 라이브러리용 API입니다.
  • 앱 개발자가 기록된 데이터의 어느 부분을 네트워크를 통해 전송할 것인지, 어디로 전송할 것인지, 어떻게 필터링, 버퍼링, 보강 및 변환할 수 있는지 구성하는 데 사용하는 API입니다.
  • 의미 체계 규칙은 원격 분석 데이터의 명명 및 콘텐츠에 대한 지침을 제공합니다. 원격 분석 데이터를 생성하는 앱과 데이터를 수신하는 도구가 다양한 종류의 데이터가 무엇을 의미하고 어떤 종류의 데이터가 유용한지에 대해 합의하여 도구가 효과적인 분석을 제공할 수 있도록 하는 것이 중요합니다.
  • 내보내기용 인터페이스입니다. 내보내기는 원격 분석 데이터를 특정 형식으로 다른 원격 분석 백 엔드로 전송할 수 있도록 하는 플러그 인입니다.
  • OTLP 유선 프로토콜은 원격 분석 데이터를 전송하기 위한 공급업체 중립 네트워크 프로토콜 옵션입니다. 일부 도구와 공급업체는 기존에 소유한 재산적 가치를 가지는 프로토콜 외에도 이 프로토콜을 지원합니다.

OTel을 사용하면 PrometheusGrafana, Microsoft의 Azure에 있는 APM 제품인 Azure Monitor 또는 OpenTelemetry와 협력하는 많은 APM 공급업체와 같은 오픈 소스 시스템을 비롯한 다양한 APM 시스템을 사용할 수 있습니다.

.NET을 비롯한 대부분의 언어와 플랫폼에 대한 OpenTelemetry 구현이 있습니다.

OpenTelemetry의 .NET 구현

.NET OpenTelemetry 구현은 .NET이 프레임워크에서 로깅, 메트릭, 활동 API를 제공하므로 다른 플랫폼과 약간 다릅니다. 즉, OTel은 라이브러리 작성자가 사용할 API를 제공할 필요가 없습니다. .NET OTel 구현은 계측을 위해 다음 플랫폼 API를 사용합니다.

.NET OTel architecture

OTel은 계측 라이브러리를 통해 해당 API 및 기타 소스에서 원격 분석을 수집한 다음, 스토리지 및 분석을 위해 이를 APM(애플리케이션 성능 모니터링) 시스템으로 내보냅니다. OTel은 업계 표준으로서 수집에 대한 일반적인 메커니즘, 원격 분석 데이터에 대한 일반적인 스키마와 의미 체계, APM이 OTel과 통합될 수 있는 방법에 대한 API라는 이점을 제공합니다. OTel을 사용하면 애플리케이션에서 OTel 표준에 어긋나는 APM 특정 API나 데이터 구조를 사용할 필요가 없습니다. APM은 APM 특정 내보내기 구성 요소를 구현하거나 원격 분석 데이터를 APM 시스템으로 내보내는 새로운 유선 표준인 OTLP를 사용할 수 있습니다.

OpenTelemetry 패키지

.NET의 OpenTelemetry는 다음과 같은 몇 가지 범주를 구성하는 일련의 NuGet 패키지로 구현됩니다.

  • Core API
  • 계측 - 이 패키지는 런타임 및 공용 라이브러리에서 계측을 수집합니다.
  • 내보내기 - Prometheus, Jaeger, OTLP와 같은 APM 시스템을 사용하여 접속합니다.

다음 표는 기본 패키지를 보여 줍니다.

패키지 이름 설명
OpenTelemetry 핵심 OTEL 기능을 제공하는 기본 라이브러리
OpenTelemetry.Instrumentation.AspNetCore ASP.NET Core 및 Kestrel 계측
OpenTelemetry.Instrumentation.GrpcNetClient 아웃바운드 gRPC 호출을 추적하기 위한 gRPC 클라이언트 계측
OpenTelemetry.Instrumentation.Http 아웃바운드 HTTP 호출을 추적하기 위한 HttpClientHttpWebRequest 계측
OpenTelemetry.Instrumentation.SqlClient 데이터베이스 작업을 추적하는 데 사용되는 SqlClient 계측
OpenTelemetry.Exporter.Console 내보내는 원격 분석을 진단하는 데 일반적으로 사용되는 콘솔용 내보내기
OpenTelemetry.Exporter.OpenTelemetryProtocol OTLP 프로토콜을 사용하는 내보내기
OpenTelemetry.Exporter.Prometheus.AspNetCore ASP.NET Core 엔드포인트를 사용하여 구현된 Prometheus용 내보내기
OpenTelemetry.Exporter.Zipkin Zipkin 추적용 내보내기

예: Prometheus, Grafana, Jaeger 사용

이 예제에서는 메트릭 수집에 Prometheus, 대시보드 생성에 Grafana, 분산 추적 표시에 Jaeger를 사용합니다.

1. 프로젝트 만들기

Visual Studio에서 ASP.NET Core Empty 템플릿을 사용하거나 다음 .NET CLI 명령을 사용하여 간단한 웹 API 프로젝트를 만듭니다.

dotnet new web

2. 메트릭 및 활동 정의 추가

다음 코드는 API가 호출된 횟수에 대한 새 메트릭(greetings.count)과 새 활동 소스(OtPrGrYa.Example)를 정의합니다.

// Custom metrics for the application
var greeterMeter = new Meter("OtPrGrYa.Example", "1.0.0");
var countGreetings = greeterMeter.CreateCounter<int>("greetings.count", description: "Counts the number of greetings");

// Custom ActivitySource for the application
var greeterActivitySource = new ActivitySource("OtPrGrJa.Example");

3. API 엔드포인트 만들기

app.MapGet("/", SendGreeting);
async Task<String> SendGreeting(ILogger<Program> logger)
{
    // Create a new Activity scoped to the method
    using var activity = greeterActivitySource.StartActivity("GreeterActivity");

    // Log a message
    logger.LogInformation("Sending greeting");

    // Increment the custom counter
    countGreetings.Add(1);

    // Add a tag to the Activity
    activity?.SetTag("greeting", "Hello World!");

    return "Hello World!";
}

참고 항목

API 정의는 OpenTelemetry와 관련된 항목을 사용하지 않습니다. 가시성에 대해 .NET API를 사용합니다.

4. OpenTelemetry 패키지 참조

NuGet 패키지 관리자 또는 명령줄을 사용하여 다음 NuGet 패키지를 추가합니다.

<ItemGroup>
   <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.5.0-rc.1" />
   <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.5.0-beta.1" />
   <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.5.0-beta.1" />
</ItemGroup>

참고 항목

OTel API가 계속해서 발전하고 있으므로 최신 버전을 사용합니다.

5. 올바른 공급자를 사용하여 OpenTelemetry 구성

var tracingOtlpEndpoint = builder.Configuration["OTLP_ENDPOINT_URL"];
var otel = builder.Services.AddOpenTelemetry();

// Configure OpenTelemetry Resources with the application name
otel.ConfigureResource(resource => resource
    .AddService(serviceName: builder.Environment.ApplicationName));

// Add Metrics for ASP.NET Core and our custom metrics and export to Prometheus
otel.WithMetrics(metrics => metrics
    // Metrics provider from OpenTelemetry
    .AddAspNetCoreInstrumentation()
    .AddMeter(greeterMeter.Name)
    // Metrics provides by ASP.NET Core in .NET 8
    .AddMeter("Microsoft.AspNetCore.Hosting")
    .AddMeter("Microsoft.AspNetCore.Server.Kestrel")
    .AddPrometheusExporter());

// Add Tracing for ASP.NET Core and our custom ActivitySource and export to Jaeger
otel.WithTracing(tracing =>
{
    tracing.AddAspNetCoreInstrumentation();
    tracing.AddHttpClientInstrumentation();
    tracing.AddSource(greeterActivitySource.Name);
    if (tracingOtlpEndpoint != null)
    {
        tracing.AddOtlpExporter(otlpOptions =>
         {
             otlpOptions.Endpoint = new Uri(tracingOtlpEndpoint);
         });
    }
    else
    {
        tracing.AddConsoleExporter();
    }
});

이 코드는 ASP.NET Core 계측을 사용하여 ASP.NET Core에서 메트릭과 활동을 가져옵니다. 또한 메트릭과 추적에 대한 Metrics 공급자와 ActivitySource 공급자를 각각 등록합니다.

이 코드는 ASP.NET Core를 사용하여 엔드포인트를 호스트하는 메트릭에 Prometheus 내보내기를 사용하므로 다음을 추가해야 합니다.

// Configure the Prometheus scraping endpoint
app.MapPrometheusScrapingEndpoint();

6. 프로젝트 실행

프로젝트를 실행한 다음, 브라우저 또는 curl을 사용하여 API에 액세스합니다.

curl -k http://localhost:7275

페이지를 요청할 때마다 만들어진 인사말 수의 수가 증가합니다. 경로 /metrics를 통해 동일한 기본 URL을 사용하여 메트릭 엔드포인트에 액세스할 수 있습니다.

6.1 로그 출력

코드의 로깅 문은 ILogger를 사용하여 출력됩니다. 출력이 콘솔로 전달되도록 콘솔 공급자는 기본적으로 활성화됩니다.

.NET에서 로그를 송신하는 방법에는 몇 가지 옵션이 있습니다.

  • stdoutstderr 출력은 Kubernetes와 같은 컨테이너 시스템에 의해 로그 파일로 리디렉션됩니다.
  • ILogger와 통합할 로깅 라이브러리를 사용하면 Serilog 또는 NLog가 포함됩니다.
  • 아래에 표시된 OTLP 또는 Azure Monitor 내보내기와 같은 OTel에 대한 로깅 공급자를 사용합니다.

6.2 메트릭에 액세스

/metrics 엔드포인트를 사용하여 메트릭에 액세스할 수 있습니다.

curl -k https://localhost:7275/
Hello World!

curl -k https://localhost:7275/metrics
# TYPE greetings_count counter
# HELP greetings_count Counts the number of greetings
greetings_count 1 1686894204856

# TYPE current_connections gauge
# HELP current_connections Number of connections that are currently active on the server.
current_connections{endpoint="127.0.0.1:7275"} 1 1686894204856
current_connections{endpoint="[::1]:7275"} 0 1686894204856
current_connections{endpoint="[::1]:5212"} 1 1686894204856
...

메트릭 출력은 엔드포인트가 요청된 시점에 메트릭의 스냅샷입니다. 결과는 Prometheus 설명 형식으로 제공되며, 이는 사람이 읽을 수 있지만 Prometheus에서 더 잘 이해할 수 있습니다. 해당 항목은 다음 단계에서 다룹니다.

6.3 추적에 액세스

서버에 대한 콘솔을 보면 콘솔 추적 내보내기에서 출력이 표시되는데, 이는 사람이 읽을 수 있는 형식으로 정보를 출력합니다. 여기에는 사용자 지정 ActivitySource 및 ASP.NET Core의 두 가지 활동이 표시됩니다.

Activity.TraceId:            2e00dd5e258d33fe691b965607b91d18
Activity.SpanId:             3b7a891f55b97f1a
Activity.TraceFlags:         Recorded
Activity.ParentSpanId:       645071fd0011faac
Activity.ActivitySourceName: OtPrGrYa.Example
Activity.DisplayName:        GreeterActivity
Activity.Kind:               Internal
Activity.StartTime:          2023-06-16T04:50:26.7675469Z
Activity.Duration:           00:00:00.0023974
Activity.Tags:
    greeting: Hello World!
Resource associated with Activity:
    service.name: OTel-Prometheus-Grafana-Jaeger
    service.instance.id: e1afb619-bc32-48d8-b71f-ee196dc2a76a
    telemetry.sdk.name: opentelemetry
    telemetry.sdk.language: dotnet
    telemetry.sdk.version: 1.5.0

Activity.TraceId:            2e00dd5e258d33fe691b965607b91d18
Activity.SpanId:             645071fd0011faac
Activity.TraceFlags:         Recorded
Activity.ActivitySourceName: Microsoft.AspNetCore
Activity.DisplayName:        /
Activity.Kind:               Server
Activity.StartTime:          2023-06-16T04:50:26.7672615Z
Activity.Duration:           00:00:00.0121259
Activity.Tags:
    net.host.name: localhost
    net.host.port: 7275
    http.method: GET
    http.scheme: https
    http.target: /
    http.url: https://localhost:7275/
    http.flavor: 1.1
    http.user_agent: curl/8.0.1
    http.status_code: 200
Resource associated with Activity:
    service.name: OTel-Prometheus-Grafana-Jaeger
    service.instance.id: e1afb619-bc32-48d8-b71f-ee196dc2a76a
    telemetry.sdk.name: opentelemetry
    telemetry.sdk.language: dotnet
    telemetry.sdk.version: 1.5.0

첫 번째는 생성된 내부 사용자 지정 활동입니다. 두 번째는 요청에 대한 ASP.NET에서 생성되며 HTTP 요청 속성에 대한 태그를 포함합니다. 둘 다 동일한 TraceId를 가지고 있다는 것을 알 수 있으며, 이는 단일 트랜잭션을 식별하고 분산 시스템에서 트랜잭션과 관련된 각 서비스의 추적을 상호 연결하는 데 사용할 수 있습니다. ID는 HTTP 헤더로 전송됩니다. ASP.NET Core는 요청을 받을 때 아무것도 없는 경우 TraceId를 할당합니다. HttpClient에는 기본적으로 아웃바운드 요청에 헤더가 포함됩니다. 각 활동에는 각 활동을 고유하게 식별하는 TraceIdSpanId의 조합인 SpanId가 있습니다. Greeter 활동은 HTTP 활동의 SpanId에 매핑되는 ParentSpanId를 통해 HTTP 활동에 부모로 지정됩니다.

이후 단계에서는 이 데이터를 Jaeger에 공급하여 분산 추적을 시각화합니다.

7. Prometheus를 사용하여 메트릭 수집

Prometheus는 메트릭 수집, 집계, 시계열 데이터베이스 시스템입니다. 각 서비스에 대한 메트릭 엔드포인트를 사용하여 이를 구성하면 주기적으로 값을 스크랩하여 시계열 데이터베이스에 저장합니다. 그런 다음, 필요에 따라 분석하고 처리할 수 있습니다.

Prometheus 형식으로 노출되는 메트릭 데이터는 프로세스 메트릭의 지정 시간 스냅샷입니다. 메트릭 엔드포인트에 대한 요청이 있을 때마다 현재 값을 보고합니다. 현재 값이 흥미로울 수 있지만, 이를 과거 값과 비교하여 추세를 확인하고 값이 이례적인지 감지할 때 더 가치가 있습니다. 서비스는 일반적으로 블랙 프라이데이에 쇼핑을 즐기는 것과 같은 시간대나 세계적인 이벤트를 기준으로 사용량이 급증합니다. 과거 추세와 비교하여 값이 비정상적인지 아니면 시간이 지남에 따라 메트릭이 서서히 악화되는지 감지할 수 있습니다.

이 프로세스는 이러한 메트릭 스냅샷의 기록을 저장하지 않습니다. 프로세스에 해당 기능을 추가하는 것은 리소스 집약적일 수 있습니다. 또한 분산 시스템에서는 일반적으로 각 노드의 인스턴스가 여러 개 있으므로, 모든 노드에서 메트릭을 수집한 다음 집계하고 이를 과거 값과 비교하고자 할 것입니다.

7.1 Prometheus 설치 및 구성

https://prometheus.io/download/에서 플랫폼에 대한 Prometheus를 다운로드하고 다운로드의 콘텐츠를 추출합니다.

실행 중인 서버의 출력 상단을 확인하여 http 엔드포인트의 포트 번호를 가져옵니다. 예시:

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7275
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5212

Prometheus YAML 구성 파일을 수정하여 HTTP 스크래핑 엔드포인트의 포트를 지정하고 더 낮은 스크래핑 간격을 설정합니다. 예시:

  scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"
    - scrape_interval: 1s # poll very quickly for a more responsive demo

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    scrape_interval: 1s # poll very quickly for a more responsive demo
    static_configs:
      - targets: ["localhost:5212"]

Prometheus를 시작하고 실행 중인 포트에 대한 출력(일반적으로 9090)을 확인합니다.

>prometheus.exe
...
ts=2023-06-16T05:29:02.789Z caller=web.go:562 level=info component=web msg="Start listening for connections" address=0.0.0.0:9090

브라우저에서 이 URL을 엽니다. 이제 Prometheus UI에서 메트릭을 쿼리할 수 있습니다. 다음 이미지에서 강조 표시된 단추를 사용하여 사용 가능한 모든 메트릭을 표시하는 메트릭 탐색기를 엽니다.

Prometheus Metrics Explorer

greetings_count 메트릭을 선택하여 값 그래프를 확인합니다.

Graph of greetings_count

8. Grafana를 사용하여 메트릭 대시보드 만들기

Grafana는 Prometheus 또는 기타 데이터 원본을 기반으로 대시보드와 경고를 만들 수 있는 대시보드 제품입니다.

플랫폼에 대한 지침에 따라 https://grafana.com/oss/grafana/에서 Grafana의 OSS 버전을 다운로드하고 설치합니다. 설치되면 Grafana는 일반적으로 포트 3000에서 실행되므로 브라우저에서 http://localhost:3000를 엽니다. 로그인해야 합니다. 기본 사용자 이름과 암호는 모두 admin입니다.

햄버거 메뉴에서 연결을 선택한 다음, 텍스트 prometheus를 입력하여 엔드포인트 형식을 선택합니다. Prometheus 데이터 원본 만들기를 선택하여 새 데이터 원본을 추가합니다.

Grafana connection to prometheus

다음 속성을 설정해야 합니다.

  • Prometheus 서버 URL: 해당하는 포트를 변경하는 http://localhost:9090/

저장 및 테스트를 선택하여 구성을 확인합니다.

성공 메시지가 표시되면 대시보드를 구성할 수 있습니다. 성공 메시지 팝업에 표시된 대시보드 빌드 링크를 클릭합니다.

시각화 추가를 선택한 다음, 방금 데이터 원본으로 추가한 Prometheus 데이터 원본을 선택합니다.

대시보드 패널 디자이너가 표시됩니다. 화면 아래쪽에서 쿼리를 정의할 수 있습니다.

Grafana query using greetings_count

greetings_count 메트릭을 선택한 다음, 쿼리 실행을 선택하여 결과를 확인합니다.

Grafana를 사용하면 다양한 메트릭을 추적하는 정교한 대시보드를 디자인할 수 있습니다.

.NET의 각 메트릭은 데이터를 분할하는 데 사용할 수 있는 키-값 쌍인 추가 차원이 있을 수 있습니다. ASP.NET 메트릭은 모두 카운터에 적용할 수 있는 여러 차원을 특징으로 합니다. 예를 들어 Microsoft.AspNetCore.Hostingcurrent-requests 카운터는 다음과 같은 차원을 갖습니다.

Attribute Type 설명 예제 현재 상태
method string HTTP 요청 메서드입니다. GET; POST; HEAD Always
scheme string 사용된 프로토콜을 식별하는 URI 체계입니다. http; https Always
host string 요청을 받은 로컬 HTTP 서버의 이름입니다. localhost Always
port int 요청을 받은 로컬 HTTP 서버의 포트입니다. 8080 기본값이 아닌 경우 추가됨(http의 경우 80, https의 경우 443)

Grafana의 그래프는 일반적으로 각각의 고유한 차원 조합에 따라 분할됩니다. Grafana 쿼리에서 차원을 사용하여 데이터를 필터링하거나 집계할 수 있습니다. 예를 들어 그래프 current_requests를 그리면 각 차원 조합에 따라 분할된 값이 표시됩니다. 호스트만을 기준으로 필터링하려면 Sum 작업을 추가하고 host를 레이블 값으로 사용합니다.

Grafana current_requests by host

9. Jaeger를 사용한 분산 추적

6단계에서는 분산 추적 정보가 콘솔에 노출되는 것을 확인했습니다. 이 정보는 활동의 작업 단위를 추적합니다. 요청 처리를 나타내기 위해 ASP.NET 활동과 같은 일부 활동은 플랫폼에서 자동으로 생성되며 라이브러리와 앱 코드도 활동을 만들 수 있습니다. 인사말 예제에는 Greeter 활동이 있습니다. 활동은 TraceId, SpanId, ParentId 태그를 사용하여 상관 관계가 지정됩니다.

분산 시스템의 각 프로세스는 자체적인 활동 정보 스트림을 생성하며, 메트릭과 마찬가지로 각 트랜잭션에 대해 수행된 작업을 시각화할 수 있도록 활동을 수집, 저장, 상호 연결하는 시스템이 필요합니다. Jaeger는 이러한 수집과 시각화를 가능하게 하는 오픈 소스 프로젝트입니다.

https://www.jaegertracing.io/download/에서 플랫폼을 위한 Jaeger의 최신 바이너리 배포 아카이브를 다운로드합니다.

그런 다음, 쉽게 액세스할 수 있는 로컬 위치에 다운로드를 추출합니다. jaeger-all-in-one(.exe) 실행 파일을 실행합니다.

./jaeger-all-in-one --collector.otlp.enabled

콘솔 출력을 확인하여 gRPC를 통해 OTLP 트래픽을 수신 대기하는 포트를 찾습니다. 예시:

{"level":"info","ts":1686963686.3854616,"caller":"otlpreceiver@v0.78.2/otlp.go:83","msg":"Starting GRPC server","endpoint":"0.0.0.0:4317"}

이 출력은 0.0.0.0:4317에서 수신 대기 중임을 알려 주므로 해당 포트를 OTLP 내보내기 대상으로 구성할 수 있습니다.

프로젝트에 대한 AppSettings.json 파일을 열고 다음 줄을 추가하여 해당하는 경우 포트를 변경합니다.

"OTLP_ENDPOINT_URL" :  "http://localhost:4317/"

속성 변경을 선택하고 추적 정보를 Jaeger로 보낼 수 있도록 인사말 프로세스를 다시 시작합니다.

이제 웹 브라우저의 http://localhost:16686/에서 Jaeger UI를 볼 수 있습니다.

Jaeger query for traces

추적 목록을 보려면 서비스 드롭다운에서 OTel-Prometheus-grafana-Jaeger를 선택합니다. 추적을 선택하면 해당 추적의 일부로 활동의 간트 차트가 표시됩니다. 각 작업을 클릭하면 활동에 대한 자세한 내용이 표시됩니다.

Jaeger Operation Details

분산 시스템에서 모든 프로세스에서 동일한 Jaeger 설치로 추적을 전송하여 시스템 전체에서 트랜잭션의 상관 관계를 지정하고자 할 수 있습니다.

앱이 자신에 대한 HTTP 호출을 만들게 하면 앱을 좀 더 흥미롭게 만들 수 있습니다.

  • 애플리케이션에 HttpClient 팩터리 추가

    builder.Services.AddHttpClient();
    
  • 중첩된 인사말 호출을 만들기 위한 새로운 엔드포인트 추가

    app.MapGet("/NestedGreeting", SendNestedGreeting);
    
  • 추적할 수도 있는 HTTP 호출을 만들도록 엔드포인트를 구현합니다. 이 경우 인공 루프에서 자신을 다시 호출합니다(실제로는 데모 시나리오에만 적용 가능).

    async Task SendNestedGreeting(int nestlevel, ILogger<Program> logger, HttpContext context, IHttpClientFactory clientFactory)
    {
        // Create a new Activity scoped to the method
        using var activity = greeterActivitySource.StartActivity("GreeterActivity");
    
        if (nestlevel <= 5)
        {
            // Log a message
            logger.LogInformation("Sending greeting, level {nestlevel}", nestlevel);
    
            // Increment the custom counter
            countGreetings.Add(1);
    
            // Add a tag to the Activity
            activity?.SetTag("nest-level", nestlevel);
    
            await context.Response.WriteAsync($"Nested Greeting, level: {nestlevel}\r\n");
    
            if (nestlevel > 0)
            {
                var request = context.Request;
                var url = new Uri($"{request.Scheme}://{request.Host}{request.Path}?nestlevel={nestlevel - 1}");
    
                // Makes an http call passing the activity information as http headers
                var nestedResult = await clientFactory.CreateClient().GetStringAsync(url);
                await context.Response.WriteAsync(nestedResult);
            }
        }
        else
        {
            // Log a message
            logger.LogError("Greeting nest level {nestlevel} too high", nestlevel);
            await context.Response.WriteAsync("Nest level too high, max is 5");
        }
    }
    

이렇게 하면 각 수준이 이전 호출의 응답을 대기하므로 요청에 대한 피라미드 모양의 더 흥미로운 그래프가 생성됩니다.

Jaeger nested dependency results

예: Azure Monitor 및 Application Insights 사용

이전 예제에서는 메트릭과 추적을 위해 별도의 오픈 소스 애플리케이션을 사용했습니다. 상용 APM 시스템에는 많은 선택지가 있습니다. Azure에서 기본 애플리케이션 모니터링 제품은 Azure Monitor의 일부인 Application Insights입니다.

통합 APM 제품의 장점 중 하나는 다양한 가시성 데이터 원본의 상관 관계를 지정할 수 있다는 것입니다. Azure Monitor를 사용하여 ASP.NET 환경을 더 쉽게 만들 수 있도록 OpenTelemetry를 구성하는 대부분의 작업을 수행하는 래퍼 패키지가 제공됩니다.

5단계에서 동일한 프로젝트를 수행하고 NuGet 참조를 단일 패키지로 바꿉니다.

<ItemGroup>
  <PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.0.0-beta.4" />
</ItemGroup>

그런 다음, OTel 초기화 코드를 다음으로 바꿉니다.

var otel = builder.Services.AddOpenTelemetry();
otel.UseAzureMonitor();
otel.WithMetrics(metrics => metrics
    .AddMeter(greeterMeter.Name)
    .AddMeter("Microsoft.AspNetCore.Hosting")
    .AddMeter("Microsoft.AspNetCore.Server.Kestrel"));
otel.WithTracing(tracing =>
{
    tracing.AddSource(greeterActivitySource.Name);
});

UseAzureMonitor()는 Application Insights에 대한 공통 계측 라이브러리와 내보내기를 추가하는 매직입니다. 사용자 지정 MeterActivitySource 이름을 등록에 추가하기만 하면 됩니다.

아직 Azure 고객이 아닌 경우 https://azure.microsoft.com/free/에서 체험 계정을 만들 수 있습니다. Azure Portal에 로그인하고 기존 Application Insights 리소스를 선택하거나 https://ms.portal.azure.com/#create/Microsoft.AppInsights를 사용하여 새 리소스를 만듭니다.

Application Insights는 포털 UI의 오른쪽 위에 있는 계측 키 및 연결 문자열을 통해 데이터를 저장하고 처리하는 데 사용할 인스턴스를 식별합니다.

Connection String in Azure Portal

Azure App Service를 사용하는 경우 이 연결 문자열은 환경 변수로 애플리케이션에 자동으로 전달됩니다. 다른 서비스를 사용하거나 로컬로 실행하는 경우 APPLICATIONINSIGHTS_CONNECTION_STRING 환경 변수를 사용하거나 appsettings.json에 전달해야 합니다. 로컬로 실행하려면 appsettings.json에 값을 추가하는 것이 가장 쉽습니다.

"AzureMonitor": {
    "ConnectionString": "InstrumentationKey=12345678-abcd-abcd-abcd-12345678..."
}

참고 항목

값을 인스턴스의 값으로 바꿉니다.

애플리케이션을 실행하면 원격 분석이 Application Insights로 전송됩니다. 이제 애플리케이션에 대한 로그, 메트릭, 분산 추적을 가져와야 합니다.

로그

App Insights logs view

메트릭

App Insights metrics view

분산 추적

App Insights transaction view