.NET 項目預設情況下 日誌是使用的 ILogger 介面,預設提供一下四種日誌記錄程式: 控制台 調試 EventSource EventLog 這四種記錄程式都是預設包含在 .NET 運行時庫中。關於這四種記錄程式的詳細介紹可以直接查看微軟的官方文檔 https://docs.microsof ...
.NET 項目預設情況下 日誌是使用的 ILogger 介面,預設提供一下四種日誌記錄程式:
- 控制台
- 調試
- EventSource
- EventLog
這四種記錄程式都是預設包含在 .NET 運行時庫中。關於這四種記錄程式的詳細介紹可以直接查看微軟的官方文檔 https://docs.microsoft.com/zh-cn/dotnet/core/extensions/logging-providers
今天給大家分享自己實現一個日誌記錄程式,繼承自 ILogger 介面,實現將日誌記錄到本地的 txt 文件中,並包含一個自動清理過期日誌的功能任務。
類庫的整體代碼結構如下:
Models 文件夾中存放 LoggerSetting.cs 是 該模塊註入服務時需要的配置參數
namespace Logger.LocalFile.Models { public class LoggerSetting { /// <summary> /// 保存天數 /// </summary> public int SaveDays { get; set; } = 7; } }
Tasks 文件夾中存放的 LogClearTask.cs 是用於自動清理過期日誌的任務,會在日誌服務註入的同時啟動,會通過配置的保存天數參數,定期刪除超過實現的日誌文件
using Common; using Logger.LocalFile.Models; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; namespace Logger.LocalFile.Tasks { public class LogClearTask : BackgroundService { private readonly int saveDays; public LogClearTask(IOptionsMonitor<LoggerSetting> config) { saveDays = config.CurrentValue.SaveDays; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { string basePath = Directory.GetCurrentDirectory().Replace("\\", "/") + "/Logs/"; if (Directory.Exists(basePath)) { List<string> logPaths = IOHelper.GetFolderAllFiles(basePath).ToList(); var deleteTime = DateTime.UtcNow.AddDays(-1 * saveDays); if (logPaths.Count != 0) { foreach (var logPath in logPaths) { var fileInfo = new FileInfo(logPath); if (fileInfo.CreationTimeUtc < deleteTime) { File.Delete(logPath); } } } } } catch { } await Task.Delay(1000 * 60 * 60 * 24, stoppingToken); } } } }
ILoggingBuilderExtensions 是應用註入服務的擴展方法,內容如下
using Logger.LocalFile.Models; using Logger.LocalFile.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace Logger.LocalFile { public static class ILoggingBuilderExtensions { public static void AddLocalFileLogger(this ILoggingBuilder builder, Action<LoggerSetting> action) { builder.Services.Configure(action); builder.Services.AddSingleton<ILoggerProvider, LocalFileLoggerProvider>(); builder.Services.AddSingleton<IHostedService, LogClearTask>(); } } }
LocalFileLogger 是日誌的保存執行方法,內容如下
using Common; using Microsoft.Extensions.Logging; using System.Text; namespace Logger.LocalFile { public class LocalFileLogger : ILogger { private readonly string categoryName; private readonly string basePath; public LocalFileLogger(string categoryName) { this.categoryName = categoryName; basePath = Directory.GetCurrentDirectory().Replace("\\", "/") + "/Logs/"; if (Directory.Exists(basePath) == false) { Directory.CreateDirectory(basePath); } } public IDisposable BeginScope<TState>(TState state) { return default!; } public bool IsEnabled(LogLevel logLevel) { if (logLevel != LogLevel.None) { return true; } else { return false; } } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) { if (IsEnabled(logLevel)) { if (state != null && state.ToString() != null) { var logContent = state.ToString(); if (logContent != null) { if (exception != null) { var logMsg = new { message = logContent, error = new { exception?.Source, exception?.Message, exception?.StackTrace } }; logContent = JsonHelper.ObjectToJson(logMsg); } var log = new { CreateTime = DateTime.UtcNow, Category = categoryName, Level = logLevel.ToString(), Content = logContent }; string logStr = JsonHelper.ObjectToJson(log); var logPath = basePath + DateTime.UtcNow.ToString("yyyyMMddHH") + ".log"; File.AppendAllText(logPath, logStr + Environment.NewLine, Encoding.UTF8); } } } } } }
LocalFileLoggerProvider 是Logger執行方法向外部的供應者,內容如下:
using Microsoft.Extensions.Logging; using System.Collections.Concurrent; namespace Logger.LocalFile { public class LocalFileLoggerProvider : ILoggerProvider { private readonly ConcurrentDictionary<string, LocalFileLogger> loggers = new(); public ILogger CreateLogger(string categoryName) { return loggers.GetOrAdd(categoryName, new LocalFileLogger(categoryName)); } public void Dispose() { loggers.Clear(); GC.SuppressFinalize(this); } } }
當我們其他項目想要使用我們這個 Logger.LocalFile 類庫時,只要添加該類庫的引用,然後在啟動服務時進行註入即可,註入方法如下:
Web 項目註入方式
//註冊本地文件日誌服務 builder.Logging.AddLocalFileLogger(options => { options.SaveDays = 7; });
控制台項目註入方式
.ConfigureLogging((hostContext, builder) => { //註冊本地文件日誌服務 builder.AddLocalFileLogger(options => { options.SaveDays = 7; }); }) .Build();
Web 項目直接在 builder 後面編寫註入就可以,控制台項目需要先 .ConfigureLogging 才可以,這是兩者的區別。
這樣就註入了我們自己編寫的日誌記錄程式,項目運行時會在項目的 Logs 文件夾中產生日誌文件,如下圖
至此 .NET 擴展 官方 Logger 實現將日誌保存到本地文件就講解完了,有任何不明白的,可以在文章下麵評論或者私信我,歡迎大家積極的討論交流,有興趣的朋友可以關註我目前在維護的一個 .net 基礎框架項目,項目地址如下 https://github.com/berkerdong/NetEngine.git https://gitee.com/berkerdong/NetEngine.git