ASP.NET Core Serisi 06: Health Checks ve Azure Application Insights’ı Kullanarak Uygulamalarınızın Sağlığını Monitor Edin

Sanırım “uygulamalarımızın sağlığı” konusu, mimari yaklaşım farketmeksizin hepimiz için her zaman önemli ve ortak bir endişe noktası olmuştur.

Bildiğimiz gibi uygulamalarımızın sağlıklı olup olmadığını görünür bir hale getirebilmek veya kolay bir yoldan öğrenebilmek, bir çok durum karşısında uygulamanın riskini en aza indirgemektedir.

Özellikle uygulamalarımız bir load-balancer arkasında multi instance olarak çalışıyorsa, trafiğin yönlendirilme işlemi veya uygulamanın yeni bir versiyona update işlemi sırasında, trafiğin hangi instance’lara gönderilip gönderilmeyeceği bilgisini load-balancer’a health check endpoint’leri ile bildirmemiz gerekmektedir. Böylece trafiğin, henüz tüm bağımlılıkları ile ayağa kalkmamış bir instance’a yönlendirilmemesini sağlamış oluyoruz.

Örneğin microservice’lerimizi kubernetes ile orchestrate etmek istiyorsak, kubernetes’in ilgili container’ın trafiği kabul etmeye hazır olup olmadığına karar verebilmesi için uygulamanın health check endpoint’ini container’ın rediness probe’u içerisinde tanımlamamız gerekmektedir.

Bu makale kapsamında ise, ASP.NET Core 2.2 den bu yana built-in olarak bizlere sunulan health checks özelliğinden bahsedip, Azure Application Insights ile nasıl entegre bir hale getirebiliriz konusuna değinmeye çalışacağım.

ASP.NET Core Health Checks, “Sql Server“, “MySql“, “Oracle“, “Mongo“, “RabbitMQ” veya “Elasticsearch” gibi uygulamanın bağımlılıklarını da dikkate alarak, health check’ler tanımlayabilmemize olanak sağlayan harika bir özelliktir.

Haydi kodlayarak bakalım.

ASP.NET Core Health Checks’in Implementasyonu

Öncelikle örnek amaçlı aşağıdaki gibi bir ASP.NET Core 3.1 Web API projesi oluşturalım.

dotnet new webapi -n Todo

Ardından “Microsoft.AspNetCore.Diagnostics.HealthChecks” paketini NuGet üzerinden projeye dahil edelim.

dotnet add package Microsoft.AspNetCore.Diagnostics.HealthChecks

Todo” ismiyle oluşturmuş olduğumuz bu API‘ın, data source olarak MongoDB kullanan bir microservice olduğunu varsayalım.

Bunun için aşağıdaki komut satırını kullanarak, Docker üzerinde hızlıca bir MongoDB instance’ı ayağa kaldıralım.

docker run -d --name my-mongo -p 27017:27017 mongo

Ardından MongoDB‘nin health durumunu gözlemleyebilmemiz için, “AspNetCore.HealthChecks.MongoDb” paketini de NuGet üzerinden projeye dahil edelim.

Şimdi API‘ın “Startup” class’ına girelim ve “ConfigureServices” method’u içererisinde health checks service’ini aşağıdaki gibi configure edelim.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    string mongoDBConnection = Configuration.GetValue("mongoDB:connection");

    services.AddHealthChecks()
            .AddMongoDb(mongodbConnectionString: mongoDBConnection,
            name: "todo-db-check",
            failureStatus: HealthStatus.Unhealthy,
            tags: new string[] { "todo-api", "mongodb" });
}

Yukarıdaki kod bloğuna baktığımızda, çok basit bir şekilde MongoDB için bir health check tanımlaması yaptığımızı görebiliriz.

App settings içerisinde ise MongoDB için connection bilgilerini aşağıdaki gibi tanımlayalım.

"mongoDB:connection": "mongodb://localhost:27017"

Şimdi ise health check’i, “/hc” path’i ile aşağıdaki gibi request pipeline’ına ekleyelim.

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapHealthChecks("/hc");
});

Ardından ilk test işlemini gerçekleştirebilmek için, API‘ı çalıştıralım ve “/hc” endpoint’ine browser üzerinden erişelim.

Gördüğümüz gibi API, database’i ile birlikte sağlıklı bir durumda.

Health check output’u default olarak “text/plain” dir. Bu nedenle sadece “Healthy”  veya “Unhealthy” gibi bir response görürüz. Tüm bağımlılıklar dahil edilmiş detaylı bir health check output’u görebilmek için ise, health check’i request pipeline’ına eklerken “HealthCheckOptions” üzerinden “ResponseWriter” özelliği ile özelleştirmemiz gerekmektedir.

Custom bir kod yazmamak için ise, “AspNetCore.HealthChecks.UI.Client” paketi ile gelen “UIResponseWriter.WriteHealthCheckUIResponse” writer’ını kullanabiliriz.

Bunun için öncelikle projeye “AspNetCore.HealthChecks.UI” paketini NuGet üzerinden dahil edelim. Ardından health check’i request pipeline’ına eklerken, aşağıdaki gibi configure edelim.

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapHealthChecks("/hc", new HealthCheckOptions()
    {
        Predicate = _ => true,
        ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
    });
});

Ardından tekrar API‘ı çalıştıralım ve “/hc” endpoint’ine browser üzerinden erişelim.

Gördüğümüz gibi şimdi daha detaylı bir health check output’una sahibiz.

Kendi Health Check’imizi Implemente Edelim

MongoDB‘nin health durumunu gözlemleyebilmek için, bizlere hazır sunulan “AspNetCore.HealthChecks.MongoDb” paketini kullandık.

NOT: Tüm hazır sunulan health checks listesine buradan erişebilirsiniz.

Peki ya custom bir ihtiyacımız varsa? Bu gibi durumlar karşısında ise, “IHealthCheck” interface’ini implemente ederek kendi health check’lerimizi oluşturabilmek mümkündür.

Örneğin “TodoHealthCheck” isminde bir class oluşturalım ve aşağıdaki gibi implemente edelim.

using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Diagnostics.HealthChecks;

namespace dotnetcore_healthchecks_sample
{
    public class TodoHealthCheck : IHealthCheck
    {
        public Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
        {
            // ...

            return Task.FromResult(HealthCheckResult.Healthy());
        }
    }
}

Ardından health checks service’ine aşağıdaki gibi dahil edelim.

services.AddHealthChecks()
        .AddMongoDb(mongodbConnectionString: mongoDBConnection,
        name: "todo-db-check",
        failureStatus: HealthStatus.Unhealthy,
        tags: new string[] { "todo-api", "mongodb" })
        .AddCheck("todo-custom-check");

Hepsi bu kadar. Şimdi tekrar “/hc” endpoint’ine browser üzereinden erişelim.

Gördüğümüz gibi oluşturmuş olduğumuz custom health check, health check output’u içerisine “todo-custom-check” ismi ile dahil edildi.

Görselleştirelim

Health check output’unu görselleştirebilmemiz için, çok da hoş bir UI mevcut. Bunun için projeye “AspNetCore.HealthChecks.UI” paketini NuGet üzerinden dahil etmemiz gerekiyor.

Bir önceki adımda, detaylı bir health check output’u elde edebilmek için zaten bu paketi projeye dahil etmiştik. Şimdi ise etkinleştirebilmek için configure etmemiz gerekmektedir.

Öncelikle aşağıdaki gibi UI‘ı, service collection’ına dahil edelim.

services.AddHealthChecksUI(setupSettings: setup =>
{
    setup.AddHealthCheckEndpoint("Todo API", "https://localhost:5555/hc");
});

Ardından request pipeline’ına, “MapHealthChecksUI” method’u ile aşağıdaki gibi ekleyelim.

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapHealthChecks("/hc", new HealthCheckOptions()
    {
        Predicate = _ => true,
        ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
    });
    endpoints.MapHealthChecksUI();
});

Health Checks UI endpoint’i default olarak, “/healthchecks-ui” olarak gelmektedir. Dilerseniz bu değeri “MapHealthChecksUI” method’u üzerinden özelleştirerek değiştirebilirsiniz.

Şimdi test edebilmek için, “/healthchecks-ui” endpoint’ine browser üzerinden erişelim.

UI üzerinden kolay bir şekilde uygulamanın ve bağımlılıklarının health durumlarını tarihsel olarak görebilmek mümkün. Ayrıca UI için bir storage provider’ı da seçerek, ilgili health check output’larını persist edebilmekte mümkündür. Provider listesine ise, buradan erişebilirsiniz.

Azure Application Insight’ın Kullanımı

Eğer sizde uygulamalarınızı Azure üzerinde host ediyorsanız, health check output’larını Azure Application Insight‘a göndermek iyi bir seçenek olacaktır.

Böylece uygulamalarımızın availability durumlarına özel chart’lar hazırlayabilir, herhangi bir hata anında ise alert’ler üretebiliriz.

Bunun için öncelikle projeye “AspNetcore.HealthChecks.Publisher.ApplicationInsights” paketini NuGet üzerinden dahil edelim.

NOT: Eğer Azure Application Insight‘a sahip değilseniz, buradan oluşturabilirsiniz.

Ardından health checks service’ine, Application Insights publisher’ı aşağıdaki gibi dahil edelim.

string instrumentationKey = Configuration.GetValue("azure:instrumentationKey");

services.AddHealthChecks()
        .AddMongoDb(mongodbConnectionString: mongoDBConnection,
        name: "todo-db-check",
        failureStatus: HealthStatus.Unhealthy,
        tags: new string[] { "todo-api", "mongodb" })
        .AddCheck("todo-custom-check")
        .AddApplicationInsightsPublisher(instrumentationKey: instrumentationKey);

Publisher’ı ekledikten sonra ise, Application Insights‘ın Azure Portal üzerinden bulabileceğimiz “instrumentationKey” bilgisini, API‘ın app settings dosyasına ekleyelim.

Hepsi bu kadar.

Şimdi API‘ı çalıştıralım ve ardından Docker üzerinde ayağa kaldırmış olduğumuz MongoDB instance’ını, aşağıdaki gibi durduralım.

Browser üzerinden “/hc” endpoint’ine eriştiğimizde, aşağıdaki gibi bir output görüyor olmalıyız.

Gördüğümüz gibi “todo-db-check” in durumu “Unhealthy” olduğu için, API‘ın da genel durumu “Unhealthy“.

Şimdi Azure Portal üzerinden, ilgili Application Insights instance’ına erişelim. Ardından “Monitoring” tab’ı altında bulunan, “Metrics” sekmesine tıklayalım.

Daha sonra filtre kısmındaki “Metric Namespace” bölümünü “azure.applicationinsights” olarak ve ardından “Metric” bölümünü “AspNetCoreHealthCheckStatus” olarak seçelim. Böylece API‘ın availability durumunu, aşağıdaki gibi görselleştirebileceğiz.

Gördüğümüz gibi API‘ın availability durumunu, zaman dilimlerine göre görselleştirebilmekteyiz. MongoDB instance’ını durdurduğumuz zaman diliminde ise, API‘ın available olmadığını yukarıdaki graph’dan görebilmekteyiz.

Ayrıca “Monitoring > Logs” sekmesi altından da daha detaylı health bilgilerine, aşağıdaki gibi “customEvents” query’leri oluşturarak erişebilmek mümkündür.

Link: https://github.com/GokGokalp/dotnetcore-healthchecks-sample

Referanslar

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-3.1&WT.mc_id=DT-MVP-5003382
https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks

Gökhan Gökalp

View Comments

  • I have microservices with each one has their own ApplicationInsights setup and healthChecks endpoints.

    I have another separate app witch monitors all my endpoints. But now I want to publish applicationInsights combine status to my new AppInsights that is for HealthCheckUI.

    Is there any way to summarize all AI with one AI publish just for healthCheck?

    • Hi, thanks for the comment and sorry for the late reply. If I understand correctly I have never done with that setup before. But just for an idea maybe you could use same AI with all apps and you can distinguish your microservices with OperationName.

  • Selamlar,
    Oncelikle detayli anlatiminiz icin tesekkur ederim. Benim cok temel bir sorum olacak. Bunu .net core ile mi yapmak zorundayiz. Yerli ve yabanci kaynaklara baktigimda sadece .net core ile orneklendirildigini gordum. .net framework ile de yapabilir miyiz?

Recent Posts

Event-Driven Architecture’larda Conditional Claim-Check Pattern’ı ile Event Boyut Sınırlarının Üstesinden Gelmek

{:en}In today’s technological age, we typically build our application solutions on event-driven architecture in order…

2 ay ago

Containerized Uygulamaların Supply Chain’ini Güvence Altına Alarak Güvenlik Risklerini Azaltma (Güvenlik Taraması, SBOM’lar, Artifact’lerin İmzalanması ve Doğrulanması) – Bölüm 1

{:tr}Bildiğimiz gibi modern yazılım geliştirme ortamında containerization'ın benimsenmesi, uygulamaların oluşturulma ve dağıtılma şekillerini oldukça değiştirdi.…

9 ay ago

Identity & Access Management İşlemlerini Azure AD B2C ile .NET Ortamında Gerçekleştirmek

{:tr}Bildiğimiz gibi bir ürün geliştirirken olabildiğince farklı cloud çözümlerinden faydalanmak, harcanacak zaman ve karmaşıklığın yanı…

1 yıl ago

Azure Service Bus Kullanarak Microservice’lerde Event’ler Nasıl Sıralanır (FIFO Consumers)

{:tr}Bazen bazı senaryolar vardır karmaşıklığını veya eksi yanlarını bildiğimiz halde implemente etmekten kaçamadığımız veya implemente…

2 yıl ago

.NET Microservice’lerinde Outbox Pattern’ı ile Eventual Consistency için Atomicity Sağlama

{:tr}Bildiğimiz gibi microservice architecture'ına adapte olmanın bir çok artı noktası olduğu gibi, maalesef getirdiği bazı…

2 yıl ago