ASP.NET Core 6/Loglama Servisinin Kullanımı

Web geliştirmede loglama önemli bir konudur. Uygulamanın durumunu, uygulama üzerinde yapılan işlemleri izlemek için loglama kullanılabilir. Log mesajları uygulama tarafında log sağlayıcılara gönderilir. Log sağlayıcıları ise görülebileceği, depolanabileceği ve işlenebileceği yerlere gönderir. ASP.NET Core'un sağladığı dahili log sağlayıcıları olduğu gibi mesajları logging framework'lara gönderen üçüncü parti sağlayıcılar da vardır. Bu framework'lar mesajları toplama ve analiz etme gibi karmaşık görevlere sahip olabilirler.

Log mesajlarının üretilmesi

değiştir

ASP.NET Core tarafından sağlanan üç log sağlayıcı bulunmaktadır. Bunlar konsol, debug ve EventSource'tur. Debug sağlayıcısı tarafından gönderilen mesajlar System.Diagnostics.Debug sınıfı tarafından işlenebilir. EventSource sağlayıcısı mesajları PerfView gibi olay izleme araçlarına gönderir. Bu bölümde konsol sağlayıcısı kullanılacaktır. Diğer bir deyişle log kayıtları direkt konsol ekranına verilecektir. Örnek:

public class EndpointSinifi
{
    public static async Task Endpoint(HttpContext context, ILogger<EndpointSinifi> logger)
    {
        logger.LogDebug("EndpointSinifi sınıfı içindeki Endpoint metodu");
    }
}

Bu adı üstünde bir endpoint sınıfıdır. Sadelik olması açısından bu sınıfın Program.cs dosyasında rota belirtiminde kullanılması gösterilmeyecektir. Loglama yapabilmemiz için mesajın hangi kategoride olduğunu belirtmemiz gerekir. Mesajın hangi kategoriye ait olduğu ILogger servisine verilen tip parametresiyle belirtilir. Geleneksel olarak log mesajını hangi sınıf üretiyorsa o kategoriye konulması tavsiye edilir. LogDebug() benzeri log mesajlarının önem seviyesini ve amacını gösteren başka metotlar da vardır. Bunlar aşağıda gösterilmiştir:

LogTrace(): Trace seviyesinde bir mesaj üretir, geliştirme sürecinde düşük seviye hata tespiti için kullanılır. Önem seviyesi: düşük
LogDebug(): Debug seviyesinde mesaj üretir, geliştirme sürecinde düşük seviye hata tespiti için ve production sürecinde oluşan sorunların sebebini tespit etmek için kullanılır. Önem seviyesi: orta
LogInformation(): Uygulamanın durumu hakkında bilgi üretir. Önem seviyesi: orta
LogError(): Uygulama tarafından yakalanmayan hataları ve istisnaları kaydetmeye yarar Önem seviyesi: yüksek
LogCritical(): Uygulama tarafından yakalanmayan kritik hataları ve istisnaları kaydetmeye yarar. Önem seviyesi: yüksek

Bu metotların önem seviyesi azaldıkça detay miktarı artar. Bu metotlar string parametre yanında Exception tipinde de parametre alabilir. Bu metotların verdiği çıktılar sunucunun konsol ekranında gözükür. Eğer gözükmüyorsa appsettings.Development.json dosyasının şöyle değiştirmeniz gerekir:

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

Benim sistemimde varsayılan olarak loglama seviyesi Default için Information'dı. Dolayısıyla gönderdiğim log mesajı konsol ekranında gözükmüyordu. Burada Default için log seviyesini en önemsiz seviye olan Trace'e çektim. Bu sayede ürettiğim log mesajları konsol ekranında gözüküyor. Burada Default, diğer kategorilerdeki log mesajlarını belirtirken Microsoft.AspNetCore ilgili kategorideki log mesajlarını belirtir. Ekrana log mesajları basan örnek bir konsol çıktısı aşağıdaki gibidir:

dbug: Microsoft.Extensions.Hosting.Internal.Host[1]
      Hosting starting
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5271
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\Users\bekir\OneDrive\Masaüstü\kitap\Loglama\Loglama\
dbug: Microsoft.Extensions.Hosting.Internal.Host[2]
      Hosting started
dbug: Loglama.EndpointSinifi[0]
      EndpointSinifi sınıfı içindeki Endpoint metodu

Burada her bir mesajın log tipi, kategorisi ve içeriği gözükmektedir.

Program.cs dosyasında loglama yapılması

değiştir

Program.cs dosyasında loglama yapabilmemiz için bir şekilde loglama servisine ulaşılması gerekir. Bunun için WebApplication sınıfı üzerindeki Logger özelliğini kullanabiliriz. Örnek:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Logger.LogDebug("Log mesajı");
app.Run();

Bu şekilde loglama yapıldığı zaman log mesajının kategorisi uygulama adı olur. Belirli bir kategori de log mesajı üretmek içinse ILoggerFactory servisini kullanırız. Örnek:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var logger = app.Services.GetRequiredService<ILoggerFactory>().CreateLogger("Kategori");
logger.LogDebug("Log mesajı");
app.Run();

Attribute kullanarak log mesajları üretme

değiştir

LogDebug() ve benzeri metotların bir alternatifi attribute kullanmaktadır. Örnek:

public partial class EndpointSinifi
{
    public static async Task Endpoint(HttpContext context, ILogger<EndpointSinifi> logger)
    {
        logger.LogDebug("EndpointSinifi sınıfı içindeki Endpoint metodu");
        LogOlustur(logger, "metin");
    }
    [LoggerMessage(0, LogLevel.Debug, "{mesaj} mesajı üretildi")]
    public static partial void LogOlustur(ILogger logger, string mesaj);
}

Attribute yoluyla log mesajı üretme daha ziyade birden fazla yerde belirli bir şablona göre log mesajı üretmemiz gerekiyorsa faydalıdır.

Minimum loglama seviyesini gösterme

değiştir

Aslında bu kısmı bölümün başında daha önce görmüştük. Burada bazı tamamlayıcı bilgiler verilecektir. Mevcut durumda appsettings.Development.json dosyasının içeriği şöyledir:

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

Burada her bir kategorinin önem seviyesi belirtilmiştir. Bir kategori olarak sınıf kullanılmışsa isim alanıyla beraber belirtilmelidir. Belirli bir isim alanının altındaki bütün sınıflar için bir önem seviyesi de belirtebiliriz. Kategori olarak bir isim alanı belrttiğimiz zaman bu isim alanının altındaki alt isim alanları da aynı loglama seviyesine sahip olacaktır. Ancak elbetteki istersek daha alt isim alanlarının (veya direkt sınıfların) önem seviyesini üst isim alanından farklı bir önem seviyesine çekerek üst isim alanının belirttiği değerin geçersiz kılınmasını sağlayabiliriz. Yani burada da kategori/alt kategori mantığı vardır.

Örneğimizde Microsoft.AspNetCore isim alanının altındaki bütün sınıf kategorilerinin önem seviyesi Warning'dir. Belirtilen kategoriler dışında kalan tüm kategorilerin önem seviyesi Default girdisi ile belirtilir. ASP.NET Core'da kullanılabilecek farklı log seviyeleri ve bu log seviyelerinde log üretmek için kullanılacak metotlar önemsizden önemliye doğru aşağıdaki tabloda gösterilmiştir:

Önem Seviye Metot
0 Trace LogTrace()
1 Debug LogDebug()
2 Information LogInformation()
3 Warning LogWarning()
4 Error LogError()
5 Critical LogCritical()
6 None

6. seviyede log mesajı üretilemez. Bu seviye, yapılandırma dosyasında "hiçbir log mesajını gösterme" anlamında kullanılır.

Request ve response'ların loglanması

değiştir

İstersek sunucuya gelen her isteği ve sonucunda döndürülen her cevabı da loglayabiliriz. Örnek (Program.cs dosyası):

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpLogging();
app.Run();

Yukarıdaki kod request pipeline'a UseHttpLogging isimli middleware'i ekler. Bu middleware gelen request'i ve giden response'u inceler ve bu request ve response hakkındaki bilgileri loglar. Bu middleware'in ürettiği loglar Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware kategorisinde ve Information önem seviyesindedir. Bu middleware'in ürettiği logları görmek için direkt bu kategoriyi, ya da üst kategorilerden birini en az Information seviyesine çekmelisiniz.

Request ve response hakkında loglanacak detaylar options pattern'iyle UseHttpLogging middleware'inin konfigure edilmesiyle belirtilebilir. Örnek (Program.cs dosyası):

using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(opts => {
    opts.LoggingFields = HttpLoggingFields.RequestMethod | HttpLoggingFields.RequestPath | HttpLoggingFields.ResponseStatusCode;
});
var app = builder.Build();
app.UseHttpLogging();
app.MapGet("/", ()=>"Merhaba dünya!");
app.Run();

Bu örneğimizde sadece request'in verb'ünün, path'ının ve response'un durum kodunun loglanmasını sağladık.