C# Log4Net學習筆記:記錄日誌到資料庫

来源:https://www.cnblogs.com/atomy/archive/2020/05/12/12873389.html
-Advertisement-
Play Games

一、數據準備 在SQL Server中創建記錄日誌的數據表LogDetail: CREATE TABLE [dbo].[LogDetail]( [LogID] [INT] IDENTITY(1,1) NOT NULL, --自增ID [LogDate] [DATETIME] NULL, --日誌時間 ...


    一、數據準備

    在SQL Server中創建記錄日誌的數據表LogDetail:

CREATE TABLE [dbo].[LogDetail](
    [LogID] [INT] IDENTITY(1,1) NOT NULL, --自增ID
    [LogDate] [DATETIME] NULL,            --日誌時間
    [LogLevel] [NVARCHAR](10) NULL,       --日誌級別
    [LogThread] [NVARCHAR](10) NULL,      --線程ID
    [Logger] [NVARCHAR](50) NULL,         --日誌名稱
    [LogMessage] [NVARCHAR](3000) NULL,   --日誌內容
 CONSTRAINT [PK_LogDetail] PRIMARY KEY CLUSTERED 
(
    [LogID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

    在此表中,日誌時間、日誌級別、線程ID、日誌名稱都是可以通過配置文件從Log4Net庫中取值的,需要重點處理的是日誌內容欄位。

    二、記錄日誌到資料庫

    2.1、配置文件

    添加一個ConfigFile文件夾,然後在其下麵新建一個Log4NetToDB.config的配置文件,接著在其屬性的複製到輸出目錄項下選擇始終複製。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net debug="false">
    <!--type:表示用哪種類型記錄日誌,log4net.Appender.ADONetAppender表示用資料庫記錄日誌。-->
    <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
      
      <!--日誌緩存寫入條數,設置為0時只要有一條就立刻寫到資料庫。-->
      <bufferSize value="0" />

      <!--資料庫連接串-->
      <!--C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Config\machine.config-->
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

      <!--資料庫連接字元串-->
      <connectionString value="Server=.;Database=Test;Uid=sa;Pwd=********;" />
      
      <!--資料庫腳本-->
      <commandText value="INSERT INTO LogDetail (LogDate,LogLevel,LogThread,Logger,LogMessage) VALUES (@LogDate,@LogLevel,@LogThread,@Logger,@LogMessage)" />
      
      <!--日誌時間-->
      <parameter>
        <parameterName value="@LogDate" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>

      <!--日誌級別-->
      <parameter>
        <parameterName value="@LogLevel" />
        <dbType value="String" />
        <size value="10" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%p" />
        </layout>
      </parameter>
      
      <!--線程ID-->
      <parameter>
        <parameterName value="@LogThread" />
        <dbType value="String" />
        <size value="10" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%t" />
        </layout>
      </parameter>

      <!--日誌名稱-->
      <parameter>
        <parameterName value="@Logger" />
        <dbType value="String" />
        <size value="50" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%logger" />
        </layout>
      </parameter>
      
      <!--日誌內容-->
      <parameter>
        <parameterName value="@LogMessage" />
        <dbType value="String" />
        <size value="3000" />
        <layout type="LinkTo.Test.ConsoleLog4Net.Utility.CustomLayout">
          <conversionPattern value="%property{LogMessage}" />
        </layout>
      </parameter>
    </appender>

    <root>
      <priority value="ALL" />
      <level value="ALL" />
      <appender-ref ref="ADONetAppender" />
    </root>
  </log4net>
</configuration>

    2.2、日誌內容處理過程

    註:日誌內容處理涉及的4個類(含幫助類)都是存放在Utility文件夾下。

    從配置的<layout type="LinkTo.Test.ConsoleLog4Net.Utility.CustomLayout">可以看出,日誌內容的取值來源於一個自定義的Layout類CustomLayout:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net.Layout;

namespace LinkTo.Test.ConsoleLog4Net.Utility
{
    public class CustomLayout : PatternLayout
    {
        /// <summary>
        /// 構造函數:把需要寫入資料庫的屬性添加進來
        /// </summary>
        public CustomLayout()
        {
            AddConverter("property", typeof(CustomLayoutConverter));
        }
    }
}

    CustomLayout類添加屬性時,類型來源於CustomLayoutConverter類:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using log4net.Core;
using log4net.Layout.Pattern;

namespace LinkTo.Test.ConsoleLog4Net.Utility
{
    public class CustomLayoutConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            if (Option != null)
            {
                //寫入指定鍵的值
                WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent));
            }
            else
            {
                //Write all the key value pairs
                WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties());
            }
        }

        /// <summary>
        /// 通過反射獲取傳入的日誌對象的某個屬性的值
        /// </summary>
        /// <param name="property"></param>
        /// <param name="loggingEvent"></param>
        /// <returns></returns>
        private object LookupProperty(string property, LoggingEvent loggingEvent)
        {
            object propertyValue = string.Empty;
            PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property);
            if (propertyInfo != null)
                propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null);
            return propertyValue;
        }


    }
}

    從配置的<conversionPattern value="%property{LogMessage}" />可以看出,日誌內容的取值來源於屬性LogMessage,而這個LogMessage,統一來源於一個實體類LogContent:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkTo.Test.ConsoleLog4Net.Utility
{
    public class LogContent
    {
        /// <summary>
        /// 日誌內容
        /// </summary>
        public string LogMessage { get; set; }

        public LogContent(string logMessage)
        {
            LogMessage = logMessage;
        }
    }
}

    2.3、幫助類

    為了簡化寫日誌的過程,封裝了一個簡單的幫助類LogHelper:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;

namespace LinkTo.Test.ConsoleLog4Net.Utility
{
    public class LogHelper
    {
        public static readonly ILog logger = LogManager.GetLogger("LinkTo.Test.ConsoleLog4Net");    //這裡的參數不能使用Type類型

        public static void Fatal(LogContent content)
        {
            logger.Fatal(content);
        }

        public static void Error(LogContent content)
        {
            logger.Error(content);
        }

        public static void Warn(LogContent content)
        {
            logger.Warn(content);
        }

        public static void Info(LogContent content)
        {
            logger.Info(content);
        }

        public static void Debug(LogContent content)
        {
            logger.Debug(content);
        }
    }
}

    2.4、測試代碼

    class Program
    {
        static void Main(string[] args)
        {
            XmlConfigurator.Configure(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "ConfigFile\\Log4NetToDB.config")));
            LogHelper.Fatal(new LogContent("This is fatal message."));
            LogHelper.Error(new LogContent("This is error message."));
            LogHelper.Warn(new LogContent("This is warn message."));
            LogHelper.Info(new LogContent("This is info message."));
            LogHelper.Debug(new LogContent("This is debug message."));

            Console.Read();
        }
    }

    2.5、運行結果

    2.6、一點優化

    每次寫日誌時,都需要進行Log4Net文件配置的話,肯定是沒有必要的:

XmlConfigurator.Configure(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "ConfigFile\\Log4NetToDB.config")));

    可以在項目的Properties\AssemblyInfo最下麵加上下麵這一句,進行全局的統一配置:

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "ConfigFile\\Log4NetToDB.config")]

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、首先準備好數據。這裡的數據不是直接從資料庫中查到的數據而是將查到的數據複製一份,兩者的數據互不影響,這樣有利於複製之後的數據可以修改。 ① 定義一個從資料庫中查到的數據的方法(service層的實現類方法),這裡省略mapper映射文件和dao層介面的方法 /** * 參數是實體類,根據參數條件 ...
  • 安裝docker 1.更新yum包 yum update 2.卸載舊版本 yum remove docker 3.安裝依賴 yum install -y yum-utils device-mapper-persistent-data lvm2 4.設置yum源 yum-config-manager ...
  • 本博客系列是學習併發編程過程中的記錄總結。由於文章比較多,寫的時間也比較散,所以我整理了個目錄貼(傳送門),方便查閱。 "併發編程系列博客傳送門" 本文是轉載問斬,原文請見 "這裡" 一、Exchanger簡介 Exchanger——交換器,是JDK1.5時引入的一個同步器,從字面上就可以看出,這個 ...
  • 1.Xpath Helper Xpath Helper 是一個面向 Xpath 初學者的 Google Chrome 插件。相對於人工找 Xpath 語法,Xpath Helper 可以實現自動分析。只要你打開一個網頁,然後點擊任何一個網路元素,Xpath Helper 就能自動幫你找出相應的 Xp ...
  • 工作的時候,尤其是自媒體,我們必備水印添加工具以保護我們的知識產權,網上有許多的線上 / 下載的水印添加工具,但他們或多或少都存在以下問題: 線上工具需要上傳到對方伺服器,信息不安全。 很多工具不具備批量處理功能。 很多工具自定義的功能太少,如水印透明度,字體等。 操作繁瑣。這裡還要註意:光理論是不 ...
  • Attribute(特性)的概念不在此贅述了,相信有點.NET基礎的開發人員都明白,用過Attribute的人也不在少數,畢竟很多框架都提供自定義的屬性,類似於Newtonsoft.JSON中JsonProperty、JsonIgnore等 自定義特性 .NET 框架允許創建自定義特性,用於存儲聲明 ...
  • 隨著 .NET 5 發佈日期的日益臨近,其對應的 C# 新版本已確定為 C# 9.0,其中新增加的特性(或語法糖)也已基本鎖定,本系列文章將向大家展示它們。 ...
  • 基於 .NET 的一個全新的、好用的 PHP SDK + Runtime: PeachPie 來啦! ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...