Aracılığıyla paylaş


.NET'te yüksek performanslı günlük kaydı

Bu LoggerMessage sınıfı, günlükleyici uzantı yöntemleri gibi LogInformation ve LogDebug'ün aksine daha az nesne tahsisi ve daha düşük hesaplama maliyeti gerektiren, önbelleğe alınabilir temsilciler oluşturma işlevselliği sunar. Yüksek performanslı günlük senaryoları için deseni LoggerMessage kullanın.

LoggerMessage günlükçü uzantısı yöntemlerine göre aşağıdaki performans avantajlarını sağlar:

  • Günlükçü uzantısı yöntemleri, gibi int"boxing" (dönüştürme) değer türlerini içine gerektirir object. Desen, LoggerMessage kesin olarak yazılan parametrelerle statik Action alanlar ve uzantı yöntemleri kullanarak kutulama yapmaktan kaçınır.
  • Günlükçü uzantısı yöntemleri, günlük iletisi her yazıldıktan sonra ileti şablonunu (adlandırılmış biçim dizesi) ayrıştırmalıdır. LoggerMessage bir şablonun yalnızca ileti tanımlandığında ayrıştırılması gerekir.

Önemli

Yüksek performanslı günlükler oluşturmak için LoggerMessage sınıfını kullanmak yerine .NET 6 ve sonraki sürümlerde LoggerMessage özniteliğini kullanabilirsiniz. , LoggerMessageAttribute modern .NET uygulamaları için yüksek oranda kullanılabilir ve yüksek performanslı bir günlük çözümü sunmak üzere tasarlanmış kaynak oluşturma günlüğü desteği sağlar. Daha fazla bilgi için bkz. Derleme Zamanı günlüğü kaynağı oluşturma (.NET Temelleri).

Örnek uygulama, öncelik sırası işleme çalışan hizmetine sahip özellikleri gösterir LoggerMessage . Uygulama, iş öğelerini öncelik sırasına göre işler. Bu işlemler gerçekleşirken, LoggerMessage deseni kullanılarak günlük iletileri oluşturulur.

Tavsiye

Günlük tutma örnek kaynak kodunun tamamı, indirilmek üzere Samples Browser'da bulunur. Daha fazla bilgi için Kod örneklerine göz atma: .NET'te günlük kaydı bölümüne bakın.

Kayıtlayıcı mesajı tanımlaması

Bir iletiyi günlüğe kaydetmek için bir temsilci oluşturmak üzere Define(LogLevel, EventId, String) kullanın. Define aşırı yüklemeler, adlandırılmış biçim dizesine (şablon) en fazla altı tür parametresi geçirmesine izin verir.

yöntemine Define sağlanan dize, ilişkilendirilmiş bir dize değil, bir şablondur. Yer tutucular, türlerin belirtilmesi sırasına göre doldurulur. Şablondaki yer tutucu adları, şablonlar arasında açıklayıcı ve tutarlı olmalıdır. Yapılandırılmış günlük verileri içinde özellik adları olarak işlev görürler. Yer tutucu adları için Pascal büyük/küçük harflerini kullanmanızı öneririz. Örneğin, {Item}, {DateTime}.

Her günlük iletisi, ActionLoggerMessage.Define tarafından oluşturulan statik bir alanda tutulur. Örneğin, örnek uygulama iş öğelerinin işlenmesine yönelik bir günlük iletisini açıklamak için bir alan oluşturur:

private static readonly Action<ILogger, Exception> s_failedToProcessWorkItem;

Action için şunu belirtin:

  • Log seviyesi.
  • Statik uzantı yönteminin adıyla benzersiz bir olay tanımlayıcısı (EventId).
  • İleti şablonu (adlandırılmış biçim dizesi).

İş öğeleri işlenmek üzere sıralandığından, çalışan hizmeti uygulaması şunları ayarlar:

  • Günlük düzeyi olarak LogLevel.Critical.
  • 13 olay kimliği, FailedToProcessWorkItem yönteminin adıyla.
  • İleti şablonunu (adlandırılmış biçim dizesi) dizeye dönüştürme.
s_failedToProcessWorkItem = LoggerMessage.Define(
    LogLevel.Critical,
    new EventId(13, nameof(FailedToProcessWorkItem)),
    "Epic failure processing item!");

LoggerMessage.Define yöntemi, günlük iletisini temsil eden bir Action temsilciyi yapılandırmak ve tanımlamak için kullanılır.

Yapılandırılmış günlükler, günlükleri zenginleştirmek amacıyla olay kimliğiyle birlikte sağlandığında olay adını kullanabilir. Örneğin, Serilog olay adını kullanır.

Action, türü kesin belirlenmiş bir genişletme yöntemiyle çağrılır. PriorityItemProcessed yöntemi, her iş öğesi işlendiğinde bir iletiyi günlüğe kaydeder. FailedToProcessWorkItem bir özel durum oluştuğunda çağrılır:

protected override async Task ExecuteAsync(
    CancellationToken stoppingToken)
{
    using (IDisposable? scope = logger.ProcessingWorkScope(DateTime.Now))
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                WorkItem? nextItem = priorityQueue.ProcessNextHighestPriority();

                if (nextItem is not null)
                {
                    logger.PriorityItemProcessed(nextItem);
                }
            }
            catch (Exception ex)
            {
                logger.FailedToProcessWorkItem(ex);
            }

            await Task.Delay(1_000, stoppingToken);
        }
    }
}

Uygulamanın konsol çıkışını inceleyin:

crit: WorkerServiceOptions.Example.Worker[13]
      Epic failure processing item!
      System.Exception: Failed to verify communications.
         at WorkerServiceOptions.Example.Worker.ExecuteAsync(CancellationToken stoppingToken) in
         ..\Worker.cs:line 27

Parametreleri bir günlük iletisine geçirmek için, statik alanı oluştururken en fazla altı tür tanımlayın. Örnek uygulama, alan için bir WorkItem türü tanımlandığında öğeleri işlerken iş öğesi ayrıntılarını Action günlüğe kaydeder.

private static readonly Action<ILogger, WorkItem, Exception> s_processingPriorityItem;

Temsilcinin günlük iletisi şablonu, sağlanan türlerden yer tutucu değerlerini alır. Örnek uygulama, öğe parametresi olarak bir WorkItem ile iş öğesi eklemek için bir temsilci tanımlar.

s_processingPriorityItem = LoggerMessage.Define<WorkItem>(
    LogLevel.Information,
    new EventId(1, nameof(PriorityItemProcessed)),
    "Processing priority item: {Item}");

İş öğesinin işlendiğini günlüğe kaydetmek için kullanılan statik genişletme yöntemi, PriorityItemProcessed iş öğesi bağımsız değişken değerini alır ve Action temsilciye iletir.

public static void PriorityItemProcessed(
    this ILogger logger, WorkItem workItem) =>
    s_processingPriorityItem(logger, workItem, default!);

Çalışan hizmetinin ExecuteAsync yönteminde, PriorityItemProcessed iletiyi günlüğe kaydetmek için çağrılır:

protected override async Task ExecuteAsync(
    CancellationToken stoppingToken)
{
    using (IDisposable? scope = logger.ProcessingWorkScope(DateTime.Now))
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                WorkItem? nextItem = priorityQueue.ProcessNextHighestPriority();

                if (nextItem is not null)
                {
                    logger.PriorityItemProcessed(nextItem);
                }
            }
            catch (Exception ex)
            {
                logger.FailedToProcessWorkItem(ex);
            }

            await Task.Delay(1_000, stoppingToken);
        }
    }
}

Uygulamanın konsol çıkışını inceleyin:

info: WorkerServiceOptions.Example.Worker[1]
      Processing priority item: Priority-Extreme (50db062a-9732-4418-936d-110549ad79e4): 'Verify communications'

Kayıt işleyici mesaj kapsamını tanımlayın

DefineScope(dize) yöntemiFunc<TResult> tanımlamak için bir temsilci oluşturur. DefineScope aşırı yüklemeler, adlandırılmış biçim dizesine (şablon) en fazla altı tür parametresi geçirmesine izin verir.

yönteminde Define olduğu gibi, yöntemine DefineScope sağlanan dize bir şablondur ve ilişkilendirilmiş bir dize değildir. Yer tutucular, türlerin belirtilmesi sırasına göre doldurulur. Şablondaki yer tutucu adları, şablonlar arasında açıklayıcı ve tutarlı olmalıdır. Yapılandırılmış günlük verileri içinde özellik adları olarak işlev görürler. Yer tutucu adları için Pascal büyük/küçük harflerini kullanmanızı öneririz. Örneğin, {Item}, {DateTime}.

yöntemini kullanarak bir dizi günlük mesajına uygulanacak bir DefineScope tanımlayın. Console günlükçü bölümünde IncludeScopes'yi etkinleştirin .

{
    "Logging": {
        "Console": {
            "IncludeScopes": true
        },
        "LogLevel": {
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        }
    }
}

Bir kapsam temsilcisini tutacak bir Func<TResult> alan ekleyerek günlük kapsamı oluşturun. Örnek uygulama (s_processingWorkScope) adlı bir alan oluşturur:

private static readonly Func<ILogger, DateTime, IDisposable?> s_processingWorkScope;

Temsilciyi oluşturmak için kullanın DefineScope . Temsilci çağrıldığında şablon bağımsız değişkenleri olarak kullanmak üzere en fazla altı tür belirtilebilir. Örnek uygulama, işlemenin başlatıldığı tarih saatini içeren bir ileti şablonu kullanır:

s_processingWorkScope =
    LoggerMessage.DefineScope<DateTime>(
        "Processing scope, started at: {DateTime}");

Günlük iletisi için statik bir uzantı yöntemi sağlayın. İleti şablonunda görünen adlandırılmış özellikler için herhangi bir tür parametresi ekleyin. Örnek uygulama, günlüğe kaydedilecek özel bir zaman damgası alır ve DateTime döndürür.

public static IDisposable? ProcessingWorkScope(
    this ILogger logger, DateTime time) =>
    s_processingWorkScope(logger, time);

Kapsam, günlük uzantısı çağrılarını bir using bloğunda sarmalar:

protected override async Task ExecuteAsync(
    CancellationToken stoppingToken)
{
    using (IDisposable? scope = logger.ProcessingWorkScope(DateTime.Now))
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                WorkItem? nextItem = priorityQueue.ProcessNextHighestPriority();

                if (nextItem is not null)
                {
                    logger.PriorityItemProcessed(nextItem);
                }
            }
            catch (Exception ex)
            {
                logger.FailedToProcessWorkItem(ex);
            }

            await Task.Delay(1_000, stoppingToken);
        }
    }
}

Uygulamanın konsol çıkışındaki günlük iletilerini inceleyin. Aşağıdaki sonuç, günlük kapsamı iletisinin dahil olduğu günlük iletilerinin öncelik sıralamasını gösterir:

info: WorkerServiceOptions.Example.Worker[1]
      => Processing scope, started at: 04/11/2024 11:27:52
      Processing priority item: Priority-Extreme (7d153ef9-8894-4282-836a-8e5e38319fb3): 'Verify communications'
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: D:\source\repos\dotnet-docs\docs\core\extensions\snippets\logging\worker-service-options
info: WorkerServiceOptions.Example.Worker[1]
      => Processing scope, started at: 04/11/2024 11:27:52
      Processing priority item: Priority-High (dbad6558-60cd-4eb1-8531-231e90081f62): 'Validate collection'
info: WorkerServiceOptions.Example.Worker[1]
      => Processing scope, started at: 04/11/2024 11:27:52
      Processing priority item: Priority-Medium (1eabe213-dc64-4e3a-9920-f67fe1dfb0f6): 'Propagate selections'
info: WorkerServiceOptions.Example.Worker[1]
      => Processing scope, started at: 04/11/2024 11:27:52
      Processing priority item: Priority-Medium (1142688d-d4dc-4f78-95c5-04ec01cbfac7): 'Enter pooling [contention]'
info: WorkerServiceOptions.Example.Worker[1]
      => Processing scope, started at: 04/11/2024 11:27:52
      Processing priority item: Priority-Low (e85e0c4d-0840-476e-b8b0-22505c08e913): 'Health check network'
info: WorkerServiceOptions.Example.Worker[1]
      => Processing scope, started at: 04/11/2024 11:27:52
      Processing priority item: Priority-Deferred (07571363-d559-4e72-bc33-cd8398348786): 'Ping weather service'
info: WorkerServiceOptions.Example.Worker[1]
      => Processing scope, started at: 04/11/2024 11:27:52
      Processing priority item: Priority-Deferred (2bf74f2f-0198-4831-8138-03368e60bd6b): 'Set process state'
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...

Günlük düzeyinde korunan iyileştirmeler

Başka bir performans iyileştirmesi, ilgili LogLevel yöntemine çağrı yapılmadan önce ILogger.IsEnabled(LogLevel) ve Log* kontrol edilerek gerçekleştirilebilir. Günlük verilen LogLevel için yapılandırılmadığında, aşağıdaki ifadeler doğrudur:

  • ILogger.Log çağrılmaz.
  • Parametreleri temsil eden object[] tahsisi engellenir.
  • Değer türü boksinginden kaçınılır.

Daha fazla bilgi için:

Ayrıca bakınız