17 Haziran 2023 Cumartesi

OpenTelemetry

     S.A. Arkadaşlar,

    Bildiğiniz gibi mikroservis yapıları bazı zorlukları da beraberinde getiriyor. Bunlardan biri de logları, metrisleri kaydetmek, izlemek ve onları merkezi bir yapı haline getirmektir. OpenTelemetry, bu zorlukları kolaylaştırmak için açık kaynaklı bir projedir. Yeni bir proje olmasına rağmen iyi bir yapıya dayanıyor. Çok çeşitli SDK'ları ve 3. parti kütüphaneleri desteklemektedir. Tüm bu konuları ele alacağımız bir yazıya hazırsak başlayalım. 

     OpenTelemetry temel olarak 3 konuyu ele alır. Bunlar log kayıtları (logging), takip süreci (tracing) ve metrikler (metrics). Bu 3 konuyu ayrı ayrı ele alacağız. Kodlarla destekleyip en son da unit testlerini yazarak yazıyı sonlandırmayı düşünüyoruz. Her zamanki gibi kodları örnek projemizde yapmakla birlikte, bu konuya ait örnekleri ayrıntılı olarak bu PR'da görebilirsiniz.

    Birden çok sdk'sı mevcut demiştik. C++, .Net, Java, Golang, Python bunlardan bazılarıdır. Dotnet tarafında desteklediği 3.parti kütüphanelerden bazıları ise SqlClient, Grdp, Http, Zepkin, Jaeger, Prometheus'dir.

    Dotnet tarafında yapılan kodlamalar genel olarak Microsoft'un kendi yapıları üzerine inşa edilmiştir. Bunları daha derli toplu ele alır ve yukarıda bahsettiğimiz yapılar için hazır hale getirir. Birçok özelliği bizim için soyutlayarak kullanıma hazır hale getirir. Normal koşullarda servislerden tek tek bu verileri ele alarak halledebiliriz, fakat OpenTelemeetry tüm bunların merkezine geçerek bu işi bizim yerimize halleder.

    Kod kısmına geçmeden önce belirtmemiz gereken bazı önemli noktalara hatırlatma yapmamız lazım. Yukarıda da bahsedildiği gibi, bu yeni bir proje ve hala sıkı bir şekilde geliştiriliyor ve önemli değişiklikler içeriyor, bu nedenle farklı kod örnekleriyle karşılaşabilirsiniz. İnternetteki kaynaklarda nispeten biraz eski olan yazılarda deprected(son sürümlerde silinecek kodlar) olmuş kod örnekleri var. Farklı şekildeki ayarlar kafanızı karıştırmasın. Örneğin şuradaki yazı çok kaliteli ve güzel olmasına rağmen (2021 yazısı) ayarları eskidir. Ayrıca paketinde bir çok RC ve beta versiyonu bulunmakta ve hangisini kullanmanız gerektiğini kafanızı karıştırabilmektedir. Bu durumda, tüm yapılandırmalar için aynı sürümleri kullanmayı deneyebilirsiniz.

//deprected code
services.AddOpenTelemetryTracing(builder =>
{
}
services.AddOpenTelemetryMetrics(builder =>
{
}
//latest code
services.AddOpenTelemetry()
.WithTracing(builder => builder.AddJaegerExporter()...)
.WithMetrics(builder => builder.AddPrometheusExporter()...)


https://opentelemetry.io/docs/
https://opentelemetry.io/docs/

    Logging: Microsoft.Extensions.Logging.Abstractions kütüphanesine bağımlılık içerir, bu nedenle projenizde Microsoft tarafından önerilen loglama kullanmalısınız, aksi takdirde CorelationID vb. ile ilgili birçok bilgiyi almakta sorunlar yaşanabilir. Bununla beraber logları düz metin(unstructured) ve json yapıları(structured) olarak 2 şekilde tutabiliyoruz. Düz metin olarak tutmak daha kolay iken, nesne olarak tutmak ise tavsiye edilen yöntemdir.

[HttpGet("log")]
public void Log()
{
_logger.LogInformation("Hello! It is {Time}", DateTime.UtcNow);
_logger.LogError("Test Error");
}
[Fact]
public void LogTest()
{
var exception = Record.Exception(() => _exampleController.Log());
Assert.Null(exception);
}

 

    TracingSystem.Diagnostics'e bağlıdır ve Microsoft'tan gelen bu verileri geliştirir ve belirli kütüphaneler için hazır hale getirir. Biz burada Zipkin ve Jaeger ile ayarlarını tamamlayıp daha sonra docker ile bu araçları ayağa kaldırarak yapmış olduğumuz kayıtları göreceğiz.

services.AddOpenTelemetry()
.WithTracing(tracingProviderBuilder => tracingProviderBuilder
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddConsoleExporter()
.AddJaegerExporter()
.AddZipkinExporter()
.AddSource("Tracing.NET")
.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService("Tracing.NET")))
[HttpGet("tracing")]
public async Task Tracing()
{
using var activity = ActivitySource.StartActivity("Example");

// note that "sampleActivity" can be null here if nobody listen events generated
// by the "SampleActivitySource" activity source.
activity?.AddTag("UserId", "AnyUser");

// Simulate a long running operation
await Task.Delay(500);
}
[Fact]
public async Task GivenInitialRequest_WhenTracingCalled()
{
// Arrange
var activitiesStarted = SetupActivityListener(); // Tüm sınıfa erişmek için

// Act
await _exampleController.Tracing();

// Assert
Assert.Single(activitiesStarted);
Assert.Contains("Example", activitiesStarted.Select(a => a.DisplayName));
Assert.NotNull(activitiesStarted.Select(a => a.Tags));
}

    Zipkin ve Jaeger araçlarını isterseniz bilgisayar ortamınıza kurabilirsiniz. Biz burada docker ile ayağa kaldırarak yola devam etmeyi tercih ettik.

docker run -d --name jaeger -p 16686:16686 -p 6831:6831/udp jaegertracing/all-in-one:1.21
docker run -d -p 9411:9411 openzipkin/zipkin



    MetricsSystem.Diagnostics'e bağlıdır. Eğer .Net tarafında bu konuya aşina iseniz, 4 metriği desteklediğini kolayca hatırlayacaksınız. Bunlar: Counter, ObservableCounter, Histogram ve ObservableGauge. Burada ise hala üzerinde çalışılmaya devam eden Prometheus aracını kullanacağız.

services.WithMetrics(metricsProviderBuilder => metricsProviderBuilder
.AddConsoleExporter()
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation()
.AddPrometheusExporter()
.AddMeter("Metrics.NET")
.AddView(
instrumentName: "components-per-order",
new ExplicitBucketHistogramConfiguration
{
Boundaries = new double[] { 1, 2, 5 }
})) //Diğer ayarlar app.UseOpenTelemetryPrometheusScrapingEndpoint();


[HttpGet("metric")]
public Counter<int> Metric()
{
//Metric
var meter = new Meter("Metrics.NET");

var counter = meter.CreateCounter<int>("RequestsOfCounter", "ms", "Example request");
meter.CreateObservableGauge("ThreadCount",
() => new[] { new Measurement<int>(ThreadPool.ThreadCount) });

// Measure the number of requests
counter.Add(1, KeyValuePair.Create<string, object>("name", "Türkiye"));

return counter;
}


[Fact]
public void MetricTest()
{
// Act
var counter = _exampleController.Metric();
Assert.NotNull(counter);
Assert.Contains("RequestsOfCounter", counter.Name);

// Act
var meter = SetupMeterListener();

// Assert
Assert.NotNull(meter);
Assert.Equal("Metrics.NET", meter.Name);
}

    Prometheus isterseniz bilgisayar ortamınıza kurabilirsiniz. Biz burada docker ile ayağa kaldırarak yola devam etmeyi tercih ettik. Ayrıca buradaki verileri kaybetmek istemiyorsanız volume yapısı için ayarlamaları da tamamlamanız gerekecektir. Ayrıntılar için buraya bakabilirsiniz.

docker run -d -p 9090:9090 prom/prometheus

-v /var/folders/prometheus.yml:/etc/prometheus/prometheus.yml //volume ayarı 

    Otel Collector ile dinamik ayarlama

    Şimdiye kadar anlattığımız kısımlar her araç olarak statik tanımlama ile ele aldık. Bunların ilgili paketlerini, docker konfigürasyonlarını hepsini manuel olarak ele almak lazım. Bunun yerine basit birkaç ayar ile dinamik olarak halledilebilir.  Bunu sağlayan yapıta otel collector deniliyor.

.AddJaegerExporter()
.AddZipkinExporter()
.AddPrometheusExporter()
.AddOtlpExporter(options => options.Endpoint = new Uri("http://localhost:4317"));

    Yukarıda static olarak belirttiğimiz araçların yerine aşağıdaki kod satırı ile bunu dinamik olarak ele alabiliriz. Bu sayede araçlara direkt olarak olan bağımlılığımız kalkar ve hızlı bir şekilde sadece ayar dosyasından istediğimiz aracı bu şekilde kullanabiliriz. Bu bize büyük bir esneklik kazandırıyor. Örnek olmasına adına aşağıya ufak bir kesit bırakıyoruz.

service:
pipelines:
traces:
receivers: [ otlp ]
processors: [ batch ]
exporters: [ logging, jaeger ]
metrics:
receivers: [ otlp ]
processors: [ batch ]
exporters: [ logging, prometheus ]
logs:
receivers: [ otlp ]
processors: [ ]
exporters: [ logging, file ]

    Tabi bunun için de yaml dosyalarını düzenlemek lazım. Kabaca otel-collector-config.yaml (yukarıdaki kod parçası bu dosyadan) ve bu ayarları kullanan docker-compose.yaml olmalı. Eğer prometheus kullanacaksanız ve buradaki verilerin kalıcı olmasını(volume) da istiyorsanız yukarıda da bahsettiğimiz gibi prometheus.yaml adında başka bir dosyasınız olması gerekir. Bunun yaml dosyalarını tamamını burada paylaşmak yerine sizi şuradaki linke yönlendireyim. Hem yazıyı daha fazla uzatmama hem de farklı ayarlar görmeniz adına daha iyi olacağını düşünüyorum.

    Özetlemek gerekirse birçok noktada hala stabil olmamasına rağmen kısa sürede sektörde adını duyurmayı başarmış ve birçok projede de kendisine yer bulmuş bir araçtır. Bununla birlikte ileride adını çok daha sık duyabiliriz.

    Yazıyı bir hadisi şerifle bitiriyoruz.

İbn Abbâs –radıyallahu anhuma-’nın merfu olarak rivâyet ettiği hadiste: Rasûlullah -sallallahu aleyhi ve sellem- şöyle buyurmuştur:

 "İki göz var ki ateş onlara değmeyecektir. Allah’ın azabından korkarak ağlayan göz ve Allah yolunda nöbet bekleyen göz."

 

Kaynakça

https://opentelemetry.io/docs/instrumentation/net/exporters/

https://code-maze.com/tracking-dotnet-opentelemetry-metrics/

https://code-maze.com/tracing-dotnet-applications-opentelemetry/

https://www.meziantou.net/monitoring-a-dotnet-application-using-opentelemetry.htm

https://www.logicmonitor.com/blog/opentelemetry-vs-prometheus (Koddan bağımsız güzel bir yazı)

Hiç yorum yok:

Yorum Gönder