Asp.net-Core
ILogger 的自定義實現
在我的項目中,我經常為我的日誌消息添加前綴。
目前我正在這樣做
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());