Asp.net-Core

ILogger 的自定義實現

  • August 27, 2019

在我的項目中,我經常為我的日誌消息添加前綴。

目前我正在這樣做

     logger.LogDebug(prefix + " some message");

我認為這將是實現自定義記錄器的好方法,在該記錄器中我設置了前綴,並且記錄器本身在每次記錄某些內容時都會附加它。

所以我創建了我的自定義記錄器類並實現了 ILogger 介面。但我不明白如何使用

   public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)

添加前綴的方法(它是自定義記錄器類的成員)。

我的完整程式碼是:

     public class CustomLogger : ILogger
     {

       private readonly ILogger _logger;
       private string _logPrefix;

       public CustomLogger(ILogger logger)
       {
         _logger = logger ?? throw new ArgumentNullException(nameof(logger));
       _logPrefix = null;
       }

       public ILogger SetLogPrefix(string logPrefix)
       {
         _logPrefix = logPrefix;
         return this;
       }

       public IDisposable BeginScope<TState>(TState state)
       {
         return _logger.BeginScope(state);
       }

       public bool IsEnabled(LogLevel logLevel)
       {
         return _logger.IsEnabled(logLevel);
       }

       public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
       {
         _logger.Log(logLevel, eventId, state, exception, formatter);
       }

     }

就個人而言,我認為這不是一個好方法,“前綴”會重複很多。你為什麼不使用日誌範圍呢?

public IActionResult GetById(string id)
{
   TodoItem item;
   using (_logger.BeginScope("Message attached to logs created in the using block"))
   {
       _logger.LogInformation(LoggingEvents.GetItem, "Getting item {ID}", id);
       item = _todoRepository.Find(id);
       if (item == null)
       {
           _logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);
           return NotFound();
       }
   }
   return new ObjectResult(item);
}

輸出

info: TodoApi.Controllers.TodoController[1002]
     => RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block
     Getting item 0
warn: TodoApi.Controllers.TodoController[4000]
     => RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using block
     GetById(0) NOT FOUND

目前,您無法更改日誌記錄模板,這是 Asp.net Core 內置基本日誌記錄的限制。對於更強大的,您可以嘗試Serilog,繼續使用介面並在類ILogger中更改一些程式碼行program.cs

您還應該查看結構化日誌記錄與基本日誌記錄的優勢

我認為您不應該在自定義記錄器中呼叫 _logger。

這將是執行時的循環呼叫,結果將是“前綴:前綴:前綴:前綴:前綴:前綴:前綴:前綴:…”

簡單地說,您可以創建一個簡單的記錄器並實現一個日誌寫入器,例如控制台、數據庫寫入器、log4net…

現在首先,您應該更改自定義記錄器,如下所示:

   public class CustomLogger : ILogger
   {
       private readonly string CategoryName;
       private readonly string _logPrefix;

       public CustomLogger(string categoryName, string logPrefix)
       {
           CategoryName = categoryName;
           _logPrefix = logPrefix;
       }

       public IDisposable BeginScope<TState>(TState state)
       {
           return new NoopDisposable();
       }

       public bool IsEnabled(LogLevel logLevel)
       {
           return true;
       }

       public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
       {
           string message = _logPrefix;
           if (formatter != null)
           {
               message += formatter(state, exception);
           }
           // Implement log writter as you want. I am using Console
           Console.WriteLine($"{logLevel.ToString()} - {eventId.Id} - {CategoryName} - {message}");
       }

       private class NoopDisposable : IDisposable
       {
           public void Dispose()
           {
           }
       }
   }

第二步,創建一個logger provider:

    public class LoggerProvider : ILoggerProvider
       {     
           public ILogger CreateLogger(string categoryName)
           {                
               return new CustomLogger(categoryName, "This is prefix: ");
           }

           public void Dispose()
           {
           }
       }

第三步,在從 Startup.cs 配置中:

   loggerFactory.AddProvider(new MicroserviceLoggerProvider());

引用自:https://stackoverflow.com/questions/53494199