.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
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...