.NET 擴展官方 Logger 實現將日誌保存到本地文件

来源:https://www.cnblogs.com/berkerdong/archive/2022/08/12/16580599.html
-Advertisement-
Play Games

.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
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在一個項目的開發過程中,通常伴隨著多套環境:本地環境 local、開發環境 dev、集成測試環境 test、用戶接受測試環境 uat、預生產環境 pre、生產環境 prod。本節的內容有些脫離真實企業開發,因為在真實的企業開發中,不會只開發一個獨立的服務,而是多個微服務。發展至今,雲原生也越來越普遍... ...
  • 《Python編程從入門到實踐》(第二版)免費下載地址~~ 內容簡介 · · · · · · 本書是針對所有層次Python讀者而作的Python入門書。全書分兩部分:第一部分介紹用Python編程所必須瞭解的基本概念,包括Matplotlib等強大的Python庫和工具,以及列表、字典、if語句、 ...
  • 首先你需要安裝RabbitMQ,安裝教程可百度查下資料即可,不做贅述,敬請諒解 啟動RabbitMQ RabbitMQ可以算是一個非同步消息隊列,在實際的開發項目中,一般是以工具模塊的方式創建,像一些SpringBoot工程所需要的基本依賴都是會有的 說明:關鍵在於誰是消息的生產者、消息的消費者;另外 ...
  • 很多小伙伴都喜歡小游戲源碼,想學一手Python做小游戲,問我做游戲難不難,要怎麼做,接下來我就介紹一下,如何用Python做游戲。 游戲演示 2048小游戲 表白彈窗 貪吃蛇 五子棋 俄羅斯方塊 超多小游戲,讓你一個爽個夠! 用PyGame做游戲非常簡單,我們今天第一篇文章,讓大家實現一個可以在地 ...
  • 我國目前並未出台專門針對網路爬蟲技術的法律規範,但在司法實踐中,相關判決已屢見不鮮,K 哥特設了“K哥爬蟲普法”專欄,本欄目通過對真實案例的分析,旨在提高廣大爬蟲工程師的法律意識,知曉如何合法合規利用爬蟲技術,警鐘長鳴,做一個守法、護法、有原則的技術人員。 案情介紹 深圳市快鴿互聯網科技有限公司 2 ...
  • 一、應用場景 大家在使用Mybatis進行開發的時候,經常會遇到一種情況:按照月份month將數據放在不同的表裡面,查詢數據的時候需要跟不同的月份month去查詢不同的表。 但是我們都知道,Mybatis是ORM持久層框架,即:實體關係映射,實體Object與資料庫表之間是存在一一對應的映射關係。比 ...
  • 背景 在 CI/CD 流程當中,測試是 CI 中很重要的部分。跟開發人員關係最大的就是單元測試,單元測試編寫完成之後,我們可以使用 IDE 或者 dot cover 等工具獲得單元測試對於業務代碼的覆蓋率。不過我們需要一個獨立的 CLI 工具,這樣我們才能夠在 Jenkins 的 CI 流程集成。 ...
  • 一:背景 上一篇我們聊到瞭如何去找 熱點函數,這一篇我們來看下當你的程式出現了 非托管記憶體泄漏 時如何去尋找可疑的代碼源頭,其實思路很簡單,就是在 HeapAlloc 或者 VirtualAlloc 時做 Hook 攔截,記錄它的調用棧以及分配的記憶體量, PerfView 會將這個 分配量 做成一個 ...
一周排行
    -Advertisement-
    Play Games
  • 1. 說明 /* Performs operations on System.String instances that contain file or directory path information. These operations are performed in a cross-pla ...
  • 視頻地址:【WebApi+Vue3從0到1搭建《許可權管理系統》系列視頻:搭建JWT系統鑒權-嗶哩嗶哩】 https://b23.tv/R6cOcDO qq群:801913255 一、在appsettings.json中設置鑒權屬性 /*jwt鑒權*/ "JwtSetting": { "Issuer" ...
  • 引言 集成測試可在包含應用支持基礎結構(如資料庫、文件系統和網路)的級別上確保應用組件功能正常。 ASP.NET Core 通過將單元測試框架與測試 Web 主機和記憶體中測試伺服器結合使用來支持集成測試。 簡介 集成測試與單元測試相比,能夠在更廣泛的級別上評估應用的組件,確認多個組件一起工作以生成預 ...
  • 在.NET Emit編程中,我們探討了運算操作指令的重要性和應用。這些指令包括各種數學運算、位操作和比較操作,能夠在動態生成的代碼中實現對數據的處理和操作。通過這些指令,開發人員可以靈活地進行算術運算、邏輯運算和比較操作,從而實現各種複雜的演算法和邏輯......本篇之後,將進入第七部分:實戰項目 ...
  • 前言 多表頭表格是一個常見的業務需求,然而WPF中卻沒有預設實現這個功能,得益於WPF強大的控制項模板設計,我們可以通過修改控制項模板的方式自己實現它。 一、需求分析 下圖為一個典型的統計表格,統計1-12月的數據。 此時我們有一個需求,需要將月份按季度劃分,以便能夠直觀地看到季度統計數據,以下為該需求 ...
  • 如何將 ASP.NET Core MVC 項目的視圖分離到另一個項目 在當下這個年代 SPA 已是主流,人們早已忘記了 MVC 以及 Razor 的故事。但是在某些場景下 SSR 還是有意想不到效果。比如某些靜態頁面,比如追求首屏載入速度的時候。最近在項目中回歸傳統效果還是不錯。 有的時候我們希望將 ...
  • System.AggregateException: 發生一個或多個錯誤。 > Microsoft.WebTools.Shared.Exceptions.WebToolsException: 生成失敗。檢查輸出視窗瞭解更多詳細信息。 內部異常堆棧跟蹤的結尾 > (內部異常 #0) Microsoft ...
  • 引言 在上一章節我們實戰了在Asp.Net Core中的項目實戰,這一章節講解一下如何測試Asp.Net Core的中間件。 TestServer 還記得我們在集成測試中提供的TestServer嗎? TestServer 是由 Microsoft.AspNetCore.TestHost 包提供的。 ...
  • 在發現結果為真的WHEN子句時,CASE表達式的真假值判斷會終止,剩餘的WHEN子句會被忽略: CASE WHEN col_1 IN ('a', 'b') THEN '第一' WHEN col_1 IN ('a') THEN '第二' ELSE '其他' END 註意: 統一各分支返回的數據類型. ...
  • 在C#編程世界中,語法的精妙之處往往體現在那些看似微小卻極具影響力的符號與結構之中。其中,“_ =” 這一組合突然出現還真不知道什麼意思。本文將深入剖析“_ =” 的含義、工作原理及其在實際編程中的廣泛應用,揭示其作為C#語法奇兵的重要角色。 一、下劃線 _:神秘的棄元符號 下劃線 _ 在C#中並非 ...