.NET'te günlük arabelleği kullanma

.NET, belirli koşullar karşılanana kadar günlüklerin yayılmasını geciktirmenize olanak sağlayan günlük arabelleği özellikleri sunar. Günlük arabelleğe alma, aşağıdaki işlemleri yapmak istediğiniz senaryolarda kullanışlıdır:

  • Belirli bir işlemden gelen tüm günlükleri, yayımlanıp yayılmayacağına karar vermeden önce toplayın.
  • Günlüklerin normal işlem sırasında gönderilmesini önleyin, ancak hatalar oluştuğunda bunları yayın.
  • Depolama alanına yazılan günlük sayısını azaltarak performansı iyileştirin.

Arabelleğe alınan günlükler, işlem belleğindeki geçici döngüsel arabelleklerde depolanır ve aşağıdaki koşullar geçerlidir:

  • Eğer arabellek doluysa, en eski günlükler silinir ve asla iletilmez.
  • Arabelleğe alınan günlükleri çıkarmak istiyorsanız, Flush() sınıfında GlobalLogBuffer veya PerRequestLogBuffer çağırabilirsiniz.
  • Arabellekleri hiçbir zaman temizlemezseniz, arabelleğe alınan günlükler sonunda uygulama çalışırken silinir, bu nedenle bu günlükler devre dışı bırakılmış gibi olur.

Kullanılabilir iki arabelleğe alma stratejisi vardır:

  • Genel arabelleğe alma: Günlükleri uygulamanın tamamında arabelleğe alır.
  • İstek başına arabelleğe alma: Varsa her bir HTTP isteği için günlükleri arabelleğe alır; aksi takdirde, genel arabelleğe alır.

Uyarı

Günlük tamponlama, .NET 9 ve sonraki sürümlerde kullanılabilir.

Günlük arabelleğe alma tüm günlük kaydı sağlayıcılarıyla uyumlu çalışır. tr-TR: Kullandığınız bir günlük sağlayıcısı IBufferedLogger arabirimini uygulamazsa, günlük arabelleği arabellek boşaltılırken her arabelleklenmiş günlük kaydında günlük yöntemlerini doğrudan çağırır.

Günlük arabelleğe alma, günlükleri geçici olarak yakalamanıza ve depolamanıza olanak tanıyarak filtreleme özelliklerini genişletir. Arabelleğe alma, anında yayma veya atma kararı vermek yerine günlükleri bellekte tutmanıza ve daha sonra bunları yayıp yaymayacağınıza karar vermenize olanak tanır.

Get started

Başlamak için genel 📦 için Microsoft.Extensions.Telemetry NuGet paketini yükleyin. alternatif olarak📦, istek başına arabelleğe alma için Microsoft.AspNetCore.Diagnostics.Middleware NuGet paketini yükleyin.

dotnet add package Microsoft.Extensions.Telemetry
dotnet add package Microsoft.AspNetCore.Diagnostics.Middleware

Paket ekleme hakkında daha fazla bilgi için bkz. dotnet add package veya Manage package dependencies in .NET applications.

Genel arabelleğe alma

Genel arabelleğe alma, günlükleri uygulamanızın tamamında arabelleğe almanızı sağlar. Filtre kurallarını kullanarak arabelleğe alınacak günlükleri yapılandırabilir ve ardından bu günlükleri dökmek için gerektiğinde arabelleği boşaltabilirsiniz.

Basit yapılandırma

Belirli bir günlük seviyesi veya altındaki genel tamponlamayı etkinleştirmek için bu seviyeyi belirtin.

// Add the Global buffer to the logging pipeline.
hostBuilder.Logging.AddGlobalBuffer(LogLevel.Information);

Yukarıdaki yapılandırma, LogLevel.Information düzeyi ve altındaki düzeylerdeki günlüklerin arabelleğe alınmasını etkinleştirir.

Dosya tabanlı yapılandırma

appsettings.jsonbir yapılandırma bölümü oluşturun, örneğin:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    },

    "GlobalLogBuffering": {
      "MaxBufferSizeInBytes": 104857600,
      "MaxLogRecordSizeInBytes": 51200,
      "AutoFlushDuration": "00:00:30",
      "Rules": [
        {
          "CategoryName": "BufferingDemo",
          "LogLevel": "Information"
        },
        {
          "EventId": 1001
        }
      ]
    }
  }
}

Önceki yapılandırma:

  • Düzey BufferingDemo ve altındaki LogLevel.Information başlayan kategorilerden günlükleri arabelleğe alır.
  • Olay kimliği 1001 olan tüm günlükleri arabelleğe alır.
  • Arabellek boyutu üst sınırını yaklaşık 100 MB olarak ayarlar.
  • Günlük kaydı boyutu üst sınırını 50 KB olarak ayarlar.
  • El ile temizleme işleminden sonra 30 saniyelik otomatik boşaltma süresini ayarlar.

Günlük arabelleğe alma işlemini yapılandırmaya kaydetmek için aşağıdaki kodu göz önünde bulundurun:

// Add the Global buffer to the logging pipeline.
hostBuilder.Logging.AddGlobalBuffer(hostBuilder.Configuration.GetSection("Logging"));

Satır içi kod yapılandırması

// Add the Global buffer to the logging pipeline.
hostBuilder.Logging.AddGlobalBuffer(options =>
{
    options.MaxBufferSizeInBytes = 104857600; // 100 MB
    options.MaxLogRecordSizeInBytes = 51200; // 50 KB
    options.AutoFlushDuration = TimeSpan.FromSeconds(30);
    options.Rules.Add(new LogBufferingFilterRule(
        categoryName: "BufferingDemo",
        logLevel: LogLevel.Information));
    options.Rules.Add(new LogBufferingFilterRule(eventId: 1001));
});

Önceki yapılandırma:

  • Düzey BufferingDemo ve altındaki LogLevel.Information başlayan kategorilerden günlükleri arabelleğe alır.
  • Olay kimliği 1001 olan tüm günlükleri arabelleğe alır.
  • Arabellek boyutu üst sınırını yaklaşık 100 MB olarak ayarlar.
  • Günlük kaydı boyutu üst sınırını 50 KB olarak ayarlar.
  • El ile temizleme işleminden sonra 30 saniyelik otomatik boşaltma süresini ayarlar.

Arabelleği temizleme

Arabelleğe alınmış günlükleri temizlemek için GlobalLogBuffer soyut sınıfını ekleyin ve Flush() yöntemini çağırın:

public class MyService
{
    private readonly GlobalLogBuffer _buffer;

    public MyService(GlobalLogBuffer buffer)
    {
        _buffer = buffer;
    }

    public void HandleException(Exception ex)
    {
        _buffer.Flush();

        // After flushing, log buffering will be temporarily suspended (= all logs will be emitted immediately)
        // for the duration specified by AutoFlushDuration.
    }
}

İstek bazlı arabelleğe alma

İstek başına arabelleğe alma, ASP.NET Core uygulamalarına özgüdür ve her HTTP isteği için günlükleri bağımsız olarak arabelleğe almanızı sağlar. Her bir istek için arabellek, istek başladığında oluşturulur ve istek sona erdiğinde kaldırılır, bu nedenle arabelleği temizlemezseniz, istek sona erdiğinde günlükler kaybolur. Bu şekilde, arabellekleri yalnızca gerçekten ihtiyaç duyduğunuzda , örneğin bir hata oluştuğunda temizlemeniz yararlı olur.

İstek başına arabelleğe alma, genel arabelleğe alma ile sıkı bir şekilde ilişkilendirilir. Günlük girdisinin istek başına arabelleğe alınması gerekiyorsa, ancak arabelleğe alma girişimi sırasında etkin bir HTTP bağlamı yoksa, bunun yerine genel arabelleğe alınacaktır. Tampon bellek boşaltması tetiklenirse, önce istek başına tampon bellek, ardından genel tampon bellek boşaltılır.

Basit yapılandırma

Yalnızca belirli bir günlük düzeyindeki veya altındaki günlükleri arabelleğe almak için:

builder.Logging.AddPerIncomingRequestBuffer(LogLevel.Information);

Dosya tabanlı yapılandırma

appsettings.jsonbir yapılandırma bölümü oluşturun:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.*": "None"
    },

    "PerIncomingRequestLogBuffering": {
      "AutoFlushDuration": "00:00:05",
      "Rules": [
        {
          "CategoryName": "PerRequestLogBufferingFileBased.*",
          "LogLevel": "Information"
        }
      ]
    }
  }
}

Önceki yapılandırma:

  • Düzey PerRequestLogBufferingFileBased. ve altındaki LogLevel.Information başlayan kategorilerden günlükleri arabelleğe alır.
  • El ile temizleme işleminden sonra 5 saniyelik bir otomatik temizleme süresi ayarlar.

Günlük arabelleğe alma işlemini yapılandırmaya kaydetmek için aşağıdaki kodu göz önünde bulundurun:

builder.Logging.AddPerIncomingRequestBuffer(builder.Configuration.GetSection("Logging"));

Satır içi kod yapılandırması

builder.Logging.AddPerIncomingRequestBuffer(options =>
{
    options.AutoFlushDuration = TimeSpan.FromSeconds(5);
    options.Rules.Add(new Microsoft.Extensions.Diagnostics.Buffering.LogBufferingFilterRule("PerRequestLogBufferingCodeBased.*", LogLevel.Information));
});

Önceki yapılandırma:

  • Düzey PerRequestLogBufferingFileBased. ve altındaki LogLevel.Information başlayan kategorilerden günlükleri arabelleğe alır.
  • El ile temizleme işleminden sonra 5 saniyelik bir otomatik temizleme süresi ayarlar.

İstek başına arabelleği boşaltma

Geçerli isteğin arabelleğe alınan günlüklerini temizlemek için PerRequestLogBuffer soyut sınıfını enjekte edin ve Flush() yöntemini çağırın.

[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
    private readonly ILogger<HomeController> _logger;
    private readonly PerRequestLogBuffer _buffer;

    public HomeController(ILogger<HomeController> logger, PerRequestLogBuffer buffer)
    {
        _logger = logger;
        _buffer = buffer;
    }

    [HttpGet("index/{id}")]
    public IActionResult Index(int id)
    {
        try
        {
            _logger.RequestStarted(id);

            // Simulate exception every 10th request
            if (id % 10 == 0)
            {
                throw new Exception("Simulated exception in controller");
            }

            _logger.RequestEnded(id);

            return Ok();
        }
        catch
        {
            _logger.ErrorMessage(id);
            _buffer.Flush();

            _logger.ExceptionHandlingFinished(id);

            return StatusCode(500, "An error occurred.");
        }
    }
}

Uyarı

Bir istek başına arabellek temizlendiğinde, genel arabellek de temizlenir.

Arabelleğe alma kuralları nasıl uygulanmaktadır?

Günlük arabelleğe alma kuralları değerlendirmesi her günlük kaydında gerçekleştirilir. Her günlük kaydı için aşağıdaki algoritma kullanılır:

  1. Günlük girdisi herhangi bir kural ile eşleşirse, hemen gönderilmek yerine arabelleğe alınır.
  2. Günlük girdisi herhangi bir kuralla eşleşmiyorsa, normal şekilde yayınlanır.
  3. Arabellek boyutu sınırına ulaşılırsa, en eski arabelleğe alınmış günlük girdileri yenilerine yer açmak için atılır (yayınlanmaz!).
  4. Kayıt girişi boyutu maksimum kayıt boyutunu aştığında, arabelleklenmez ve normal şekilde yayılır.

Her günlük kaydı için algoritma şunları denetler:

  • Günlük düzeyi kuralın günlük düzeyiyle eşleşiyorsa (buna eşit veya ondan düşükse).
  • Kategori adı kuralın CategoryName ön eki ile başlıyorsa.
  • Olay kimliği kuralın EventIdile eşleşiyorsa.
  • Olay adı kuralın EventNameile eşleşiyorsa.
  • Herhangi bir öznitelik kuralın Attributes ile eşleşiyorsa.

Çalışan bir uygulamada arabellek filtreleme kurallarını değiştirme

Hem genel arabelleğe alma hem de istek başına arabelleğe alma çalışma zamanı yapılandırma güncelleştirmelerini IOptionsMonitor<TOptions> arabirimi aracılığıyla destekler. Dosya Yapılandırma Sağlayıcısı gibi yeniden yüklemeleri destekleyen bir yapılandırma sağlayıcısı kullanıyorsanız, uygulamayı yeniden başlatmadan çalışma zamanında filtreleme kurallarını güncelleştirebilirsiniz.

Örneğin, uygulamanızı appsettings.json ile başlatabilirsiniz, bu da LogLevel.Information ile başlayan PerRequestLogBufferingFileBased. düzey ve kategoriye sahip günlükler için günlük arabelleğe almayı etkinleştirir.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.*": "None"
    },

    "PerIncomingRequestLogBuffering": {
      "AutoFlushDuration": "00:00:05",
      "Rules": [
        {
          "CategoryName": "PerRequestLogBufferingFileBased.*",
          "LogLevel": "Information"
        }
      ]
    }
  }
}

Uygulama çalışırken ,appsettings.json aşağıdaki yapılandırmayla güncelleştirebilirsiniz:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.*": "None"
    },

    "PerIncomingRequestLogBuffering": {
      "Rules": [
        {
          "LogLevel": "Information"
        }
      ]
    }
  }
}

Yeni kurallar otomatik olarak uygulanır. Örneğin, önceden belirtilen yapılandırmada LogLevel.Information düzeyinde olan tüm günlükler arabelleğe alınacaktır.

Performansla ilgili dikkat edilmesi gerekenler

Günlük arabelleğe alma, bellek kullanımı ile günlük depolama maliyetleri arasında bir ödünleşim sunar. Bellekte günlükleri arabelleklemek, aşağıdakileri gerçekleştirmenizi sağlar:

  1. Çalışma zamanı koşullarına göre günlükleri seçmeli olarak yayın.
  2. Gereksiz günlükleri depolama alanına yazmadan bırakın.

Ancak özellikle yüksek aktarım hızına sahip uygulamalarda bellek tüketimine dikkat edin. Aşırı bellek kullanımını önlemek için uygun arabellek boyutu sınırlarını yapılandırın.

En iyi yöntemler

  • Uygulamanızın bellek kısıtlamalarına göre uygun arabellek boyutu sınırları ayarlayın.
  • Web uygulamaları için istek başına arabelleğe almayı kullanarak günlük kayıtlarını her bir istek için ayrı tutun.
  • Bellek kullanımını ve günlük kullanılabilirliğini dengelemek için otomatik temizleme süresini dikkatle yapılandırın.
  • Önemli olaylar (hatalar ve uyarılar gibi) için açık temizleme tetikleyicileri uygulayın.
  • Kabul edilebilir sınırlar içinde kaldığından emin olmak için üretimdeki arabellek belleği kullanımını izleyin.

Sınırlamalar

  • Günlük tamponlama, .NET 8 ve önceki sürümlerde desteklenmez.
  • Günlüklerin sırasının korunması garanti değildir. Ancak, özgün zaman damgaları korunur.
  • Her bir kayıt sağlayıcısı için özel yapılandırma desteklenmez. Tüm sağlayıcılar için aynı yapılandırma kullanılır.
  • Günlük kapsamları desteklenmez. Bu, BeginScope yöntemini kullanırsanız, arabelleğe alınan günlük kayıtlarının kapsamla ilişkilendirilmeyeceği anlamına gelir.
  • Özgün günlük kaydının tüm bilgileri korunmaz. Günlük arabelleği içten içe BufferedLogRecord sınıfını boşaltma sırasında kullanır ve şu özellikleri her zaman boştur:

Ayrıca bakınız