.NET 擴充套件 官方 Logger 實現將紀錄檔儲存到本地檔案

2022-08-12 18:02:20

.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 基礎框架專案,專案地址如下