OpenTelemetry (OTel) to przełomowe rozwiązanie w zakresie observability dla aplikacji .NET, oferujące zunifikowany sposób zbierania, przetwarzania i eksportowania danych telemetrycznych. Technologia ta, uznana za przemysłowy standard, pozwala programistom łatwo wdrażać pełne monitorowanie aplikacji w oparciu o trzy filary: distributed tracing, metrics oraz structured logging. W środowisku .NET, OpenTelemetry bazuje na natywnych API platformy, zapewniając najwyższą wydajność i pełną integrację z architekturą frameworka. Praktyczne wdrożenie OTel wymaga nie tylko zrozumienia koncepcji teoretycznych, ale też umiejętności efektywnej konfiguracji, optymalizacji oraz integracji z narzędziami monitorującymi. Niniejszy artykuł kompleksowo prezentuje wykorzystanie OpenTelemetry w .NET — zarówno od strony podstaw, jak i zaawansowanych implementacji, umożliwiając budowę skalowalnych i niezawodnych systemów observability.

Architektura i kluczowe cechy OpenTelemetry w .NET

Implementacja OTel w .NET odróżnia się od innych ekosystemów dzięki filozofii Microsoft zakładającej dostępność natywnych API do logowania, metryk i śledzenia aktywności. Framework .NET dostarcza natywne interfejsy programistyczne do logowania, metryk oraz distributed tracing bezpośrednio jako część platformy, co oznacza brak konieczności wprowadzania dodatkowych API przez OpenTelemetry.

Do instrumentacji aplikacji wykorzystywane są:

  • interfejs Microsoft.Extensions.Logging.ILogger<TCategoryName> do logowania,
  • System.Diagnostics.Metrics.Meter dla metryk,
  • System.Diagnostics.ActivitySource i System.Diagnostics.Activity dla distributed tracingu,
  • inne źródła poprzez instrumentacyjne biblioteki.

Pakiety OTel w .NET są podzielone logicznie na:

  • Core API — główna biblioteka implementująca wspólną funkcjonalność OTel,
  • Instrumentacyjne biblioteki — obsługujące zbieranie danych telemetrycznych z runtime’u i popularnych bibliotek, np. OpenTelemetry.Instrumentation.AspNetCore, OpenTelemetry.Instrumentation.SqlClient,
  • Exportery — exportujące dane do systemów APM (Prometheus, Jaeger, OTLP, Zipkin).

Wykorzystanie OpenTelemetry pozwala na uniezależnienie się od konkretnych narzędzi APM, dzięki czemu łatwo można przełączać się między różnymi systemami observability bez konieczności modyfikowania kodu aplikacji.

Integracja z .NET Aspire jeszcze bardziej rozszerza możliwości observability — gotowe szablony projektów zawierają domyślną konfigurację ServiceDefaults zintegrowaną z bibliotekami OpenTelemetry, usprawniając wdrażanie monitorowania w aplikacjach rozproszonych.

Distributed tracing w .NET — jak to działa?

Distributed tracing to kluczowa metodologia rejestrująca czasy rozpoczęcia i zakończenia operacji, wraz z dodatkowymi danymi pomocniczymi o każdej aktywności.

W aplikacji ASP.NET Core, distributed tracing pozwala śledzić:

  • czas rozpoczęcia i zakończenia żądania HTTP,
  • istotne metadane takie jak metoda HTTP, URL czy status odpowiedzi,
  • zapytania do baz danych i zewnętrznych API, o ile te również obsługują OTel,
  • pełną ścieżkę żądania od klienta przez API do bazy danych i z powrotem.

Dzięki temu można dokładnie obserwować, gdzie poświęcany jest czas oraz w którym miejscu pojawiają się ewentualne opóźnienia lub wyjątki.

Aby skonfigurować distributed tracing w ASP.NET Core, zalecane jest użycie pakietów:

  • OpenTelemetry,
  • OpenTelemetry.Instrumentation.AspNetCore,
  • OpenTelemetry.Extensions.Hosting,
  • OpenTelemetry.Exporter.Console.

Konfiguracja odbywa się zwykle przez IServiceCollection na etapie startu aplikacji, poprzez builder.Services.AddOpenTelemetry().WithTracing(), gdzie można ustawić nazwę usługi, skonfigurować resource builder, dodać automatyczną instrumentację ASP.NET Core (AddAspNetCoreInstrumentation()) oraz wybrać eksporter (np. AddConsoleExporter()).

Automatyczna instrumentacja pozwala na zbieranie i prezentowanie pełnego śladu rozproszonych operacji — zarówno dla żądań HTTP, jak i zapytań do bazy danych czy wywołań zewnętrznych API. W bardziej zaawansowanych scenariuszach można dodać eksportery dla platform takich jak Jaeger czy Zipkin.

Zbieranie i analiza metryk w OpenTelemetry

Metryki w OTel dostarczają ilościowych danych o zachowaniu systemu — m.in. dotyczących wykorzystania zasobów lub wydajności aplikacji.

Dzięki metrykom możliwy jest monitoring takich parametrów jak zużycie CPU, ilość pamięci RAM, liczba żądań HTTP czy czas trwania operacji.

Dla wdrożenia metryk w .NET 8: MeterProvider tworzy instancje Meter i instrumentuje wskazane pomiary. Przykłady wdrożeń, jak np. BookStore WebAPI, pokazują użycie OTLP exporter (OpenTelemetry.Exporter.OpenTelemetryProtocol) do przesyłania danych metrycznych do Collector’a, a następnie do Prometheusa i wizualizacji w Grafanie.

Najczęściej wykorzystywane metryki procesowe prezentuje poniższa lista:

  • process.memory.usage – ilość pamięci fizycznej przydzielonej procesowi;
  • process.memory.virtual – objętość zarezerwowanej pamięci wirtualnej;
  • process.cpu.time – czas wykorzystania CPU przez proces (w sekundach);
  • process.cpu.count – liczba dostępnych procesorów/rdzeni dla procesu;
  • process.threads – liczba aktywnych wątków procesu.

Dane te pozwalają ocenić, jak aplikacja wykorzystuje dostępne zasoby i w jaki sposób kształtują się jej parametry wydajnościowe.

Konfigurując metryki w .NET 8, warto dodać nie tylko metryki aplikacyjne, ale też te wbudowane i obsługiwane przez bibliotekę .NET — jak np. „Microsoft.AspNetCore.Hosting”, „Microsoft.AspNetCore.Server.Kestrel”. Dla komunikacji sieciowej — „System.Net.Http” i „System.Net.NameResolution”.

Histogramy pozwalają analizować rozkład wartości, np. latencję czy rozmiar odpowiedzi, grupując je w koszyki (buckets). Zaleca się dostosowywanie granic buckets do potrzeb biznesowych, by lepiej odwzorować rozkład danych telemetrycznych.

Integracja logowania w OpenTelemetry dla .NET

Logowanie w OTel opiera się na istniejącym interfejsie ILogger — nie ma potrzeby zmiany komunikatów ani istniejącego kodu logiki aplikacji. Wystarczy skonfigurować logger do korzystania z OpenTelemetry jako providera.

Logi mogą zawierać dowolne dane (niezwiązane bezpośrednio z tracingiem czy metrykami), jednak często koreluje się je z spans (zdarzeniami tracing) dla zwiększenia czytelności danych. Przemyślana konfiguracja umożliwia integrację structured logging oraz korelację z metrics i tracing.

Podstawowa konfiguracja wymaga:

  • instalacji OpenTelemetry.Exporter.Console,
  • dodania AddOpenTelemetry do loggera,
  • użycia AddConsoleExporter() — do testów lokalnych lub ustawienia eksportera OTLP dla produkcji.

W .NET 8 Microsoft zapewnia natywną korelację logów z tracing, co umożliwia automatyczne dołączanie Trace ID i Span ID do logów (przy ustawieniu OTEL_LOGS_INCLUDE_TRACE_CONTEXT=true). Platformy takie jak SigNoz lub Honeycomb ułatwiają łączenie i analizowanie logów z trace’ami, znacząco skracając czas debugowania incydentów produkcyjnych.

Logi można przesyłać do różnych systemów observability dzięki elastycznej konfiguracji zmiennych środowiskowych, np.:

  • OTEL_SERVICE_NAME,
  • OTEL_EXPORTER_OTLP_ENDPOINT,
  • OTEL_EXPORTER_OTLP_HEADERS (np. dla Honeycomb),
  • OTEL_EXPORTER_OTLP_INSECURE (np. dla collectorów on-premise).

Włączenie IncludeFormattedMessage oraz IncludeScopes przy konfiguracji loggera ułatwia późniejszą analizę i korelację logów.

Przykłady praktycznych wdrożeń OpenTelemetry w .NET

Aby skutecznie wdrożyć OpenTelemetry w pełni profesjonalnej aplikacji, należy systematycznie skonfigurować wszystkie trzy filary monitorowania: tracing, metrics oraz logging.

Podstawowe kroki implementacji prezentują się następująco:

  • definicja service name – identyfikacja serwisu dla tagowania danych telemetrycznych;
  • inicjalizacja OpenTelemetry builder – z wykorzystaniem otel.ConfigureResource i otel.WithTracing/WithMetrics;
  • dodanie instrumentacji ASP.NET Core oraz custom meters/tracing sources;
  • wybór i konfiguracja eksportera (np. Prometheus dla metryk, Jaeger/OTLP dla tracing, dedykowane narzędzie do logów);
  • udostępnienie endpointu do Prometheus’a – przez app.MapPrometheusScrapingEndpoint();
  • pełne oznaczenie danych metadanymi źródłowymi aplikacji.

Dzięki temu cała aplikacja eksportuje metryki do Prometheus, ślady do Jaeger (lub OTLP), a logi są przesyłane zgodnie z konfiguracją providera.

Przykład systemu order processing demonstruje praktyczną instrumentację endpoints (POST /order oraz GET /order/{id}) z wykorzystaniem OTel, pozwalając nie tylko monitorować czas odpowiedzi, ale też błędy, wywołania zewnętrznych serwisów czy operacje biznesowe.

Wydajność i optymalizacja OpenTelemetry w .NET

Implementacja OpenTelemetry w .NET została zoptymalizowana pod kątem minimalnego wpływu na wydajność aplikacji. Podstawą instrumentacji systemu jest klasa Activity, będąca częścią BCL, niezależną od OTel lub innych narzędzi open source. Shim stworzony w ramach projektu OpenTelemetry pozwala zachować spójność terminologii między różnymi językami programowania, bez dodatkowego narzutu wydajnościowego.

Praktyka pokazuje, że overhead związany z OTel jest pomijalny dla większości aplikacji biznesowych — ewentualne wąskie gardła należy szukać w samym kodzie lub warstwie .NET, nie w telemetryce.

Kluczowy element optymalizacji stanowi batch processor wykorzystywany niemal w każdym środowisku produkcyjnym:

  • Batch processor zwiększa efektywność, niezawodność i ekonomiczność transmisji danych telemetrycznych;
  • grupuje, agreguje i kompresuje spans, metryki oraz logi przed wysłaniem dalej w pipeline,
  • redukuje liczbę połączeń sieciowych, zwiększa efektywność kompresji i znacząco obniża koszty sieciowe.
  • wysyła duże batch’e rzadziej (zamiast wielu drobnych żądań), co ułatwia sprawne przyjmowanie danych przez backend.

Dzięki tym mechanizmom OpenTelemetry stanowi skalowalne, bezpieczne i wydajne rozwiązanie monitorowania nawet dla najbardziej rozbudowanych środowisk produkcyjnych .NET.

Najlepsze praktyki i produkcyjne wdrożenie OpenTelemetry

Efektywne wdrożenie OTel w produkcji wymaga przestrzegania kilku fundamentalnych zasad:

  • Semantic Conventions – stosowanie wspólnego schematu metadanych gwarantuje spójność, czytelność i efektywną korelację sygnałów telemetrycznych;
  • przestrzeganie rekomendacji dotyczących nazewnictwa atrybutów: używanie małych liter, unikalnych nazw, separation przez kropki, snake case dla złożonych nazw,
  • odpowiednia konfiguracja zmiennych środowiskowych – zwłaszcza OTEL_RESOURCE_ATTRIBUTES, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SAMPLER;
  • konfiguracja bezpieczeństwa zgodnie ze standardami organizacji oraz najlepszymi praktykami OTel.

Świadome podejście do architektury, metadanych oraz ciągłe monitorowanie wydajności stanowią klucz do skutecznego i wysokowydajnego monitorowania aplikacji .NET z wykorzystaniem OpenTelemetry.