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

sınıfı, LoggerMessage ve LogDebuggibi LogInformation günlükçü uzantısı yöntemlerine kıyasla daha az nesne ayırması ve daha az hesaplama yükü gerektiren önbelleğe alınabilir temsilciler oluşturma işlevselliğini 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üğü kaynak 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, günlük iletileri deseni LoggerMessage kullanılarak oluşturulur.

İpucu

Günlük örneği kaynak kodunun tümü, indirilebilmeniz için Samples Browser'da bulunur. Daha fazla bilgi için bkz . Kod örneklerine göz atma: .NET'te günlüğe kaydetme.

Günlükçü iletisi tanımlama

bir iletiyi günlüğe kaydetmek üzere temsilci Action oluşturmak için 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 görev yaparlar. Yer tutucu adları için Pascal büyük/küçük harflerini kullanmanızı öneririz. Örneğin, {Item}, {DateTime}.

Her günlük iletisi, Action LoggerMessage.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;

için Actionşunu belirtin:

  • Günlük düzeyi.
  • 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.
  • yönteminin adıyla FailedToProcessWorkItem olay kimliği13.
  • Bir dizeye ileti şablonu (adlandırılmış biçim dizesi).
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ük depoları, günlüğü zenginleştirmek için olay kimliğiyle birlikte sağlandığında olay adını kullanabilir. Örneğin, Serilog olay adını kullanır.

Action türü kesin olarak belirlenmiş bir uzantı yöntemiyle çağrılır. yöntemi, PriorityItemProcessed bir iş öğesi her işlendiğinde bir iletiyi günlüğe kaydeder. FailedToProcessWorkItem bir özel durum oluşursa ve 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ımlayarak öğeleri işlerken iş öğesi ayrıntılarını günlüğe Action 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 parametresinin olduğu bir iş öğesi eklemek için bir WorkItemtemsilci 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 statik uzantı yöntemi, PriorityItemProcessediş öğesi bağımsız değişken değerini alır ve temsilciye Action geçirir:

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'

Günlükçü ileti kapsamını tanımlama

DefineScope(dize) yöntemi, günlük kapsamı tanımlamak için bir Func<TResult>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 görev yaparlar. Yer tutucu adları için Pascal büyük/küçük harflerini kullanmanızı öneririz. Örneğin, {Item}, {DateTime}.

yöntemini kullanarak DefineScope bir dizi günlük iletisine uygulanacak bir günlük kapsamı tanımlayın. appsettings.json konsol günlükçü bölümünde etkinleştirinIncludeScopes:

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

Günlük kapsamı oluşturmak için kapsam için temsilci tutacak bir Func<TResult> alan ekleyin. Örnek uygulama (İç/LoggerExtensions.cs) adlı s_processingWorkScope 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 DateTime kaydetmek için özel bir zaman damgası alır ve döndürür _processingWorkScope:

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 Log* yönteme LogLevelçağrı yapılmadan önce ile denetlenerek ILogger.IsEnabled(LogLevel) yapılabilir. Günlük belirtilen LogLeveliçin yapılandırılmadığında aşağıdaki deyimler doğrudur:

  • ILogger.Log çağrılmaz.
  • Parametreleri temsil eden ayırma object[] işlemi engellenir.
  • Değer türü kutulamasından kaçınılır.

Daha fazla bilgi için:

Ayrıca bkz.