程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 搭建一套自己實用的.net架構(2)【日志模塊-log4net】,.net-log4net

搭建一套自己實用的.net架構(2)【日志模塊-log4net】,.net-log4net

編輯:C#入門知識

搭建一套自己實用的.net架構(2)【日志模塊-log4net】,.net-log4net


       先談談簡單的模塊,日志。在系統中日志模塊是必須的,什麼系統日志,操作日志,調試日志。這裡用的是log4net

對log4net還不熟悉的小伙伴們趕快去搜索基礎教程哦, 我這裡就不溫故了。

       那麼有人要問了,log4net確實很強大,而且我們也會用。還要單獨寫一篇文章來介紹,有必要嗎?

我簡單的舉兩個場景:

1:log4net寫入DB 還需要在 log4net中配置數據庫連接字符串,   我想log4net 和 我的 connectionStrings 用1個配置不行嗎?

2:log4net寫入參數擴展問題,我配置文件想寫入ip地址,那我代碼還要定義一個ip的參數。 那我再擴展,還需要再定義,這改動量太大了,能不能只傳一個實體類,讓log4net自己去映射那?這樣我就可以寫一些通用的方法,好多項目都可以直接拿過來用,代碼修改量也少了點。

有人覺得這都不是問題,高手請跳過。

我這裡將日志模塊單獨封裝了一個HY.Log,截圖如下:

 看圖有點亂,下面我給大家捋一捋(念lv  念成lu的去面壁思過  ):

 

第一步:實現自定義參數

我們要在PatternConverter文件夾中定義一些可擴展參數,這樣就可以在log4net配置文件中隨心使用了,哪截圖中我實現了獲取客戶端ip、獲取服務器端ip

或許服務器mac地址。

就拿ClientIpPatternConverter.cs來說需要繼承log4net下  log4net.Layout.Pattern.PatternLayoutConverter類,來實現擴展。

using System.IO;
using log4net.Core;
using log4net.Layout.Pattern;

namespace HY.Log.PatternConverter
{
    /// <summary>
    /// B/S 客戶端地址擴展
    /// </summary>
    internal class ClientIpPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            writer.Write(HY.Utilities.IPHelper.GetRemoteIPAddress());           
        }
    }
}

 接著在分別實現 MAC、服務端IP、 以及其它你任何想擴展的參數。

 

ObjectPatternConverter.cs 這個類就比較特殊了。這個自定義參數其實是讓你傳入一個實體類,然後通過反射技術,讓log4net通過配置文件的 配置自動映射要傳入的值。

上面的類 是針對特定的通用功能擴展,這個類只需要定義一個即可。

using System.IO;
using System.Reflection;
using log4net.Core;
using log4net.Layout.Pattern;

namespace HY.Log.PatternConverter
{
    internal class ObjectPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            if (Option != null)
            {
                // Write the value for the specified key
                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;
        }
    }
}

 

 

 第二步:實現log4net自定義布局,將自定義參數進行注冊

 CustomLayout.cs

using HY.Log.PatternConverter;
using log4net.Layout;

namespace HY.Log
{
    /// <summary>
    /// 定義log日志布局的參數信息
    /// </summary>
    public class CustomLayout : PatternLayout
    {
        /// <summary>
        /// 構造函數
        /// </summary>
        public CustomLayout()
        {
            #region 內部自定義
            AddConverter("ServerIP", typeof(ServerIpPatternConverter));
            AddConverter("ClientIP", typeof(ClientIpPatternConverter));
            AddConverter("MAC", typeof(MacPatternConverter));
            #endregion

            #region 支持開發人員自定義
            AddConverter("Object", typeof(ObjectPatternConverter));
            #endregion
        }
    }
}

代碼將自定義的參數以 key value 的形式進行注冊, 以後我們再log4net進行配置的時候 就要記住這些關鍵字了, 這都是你自己定義的。

你敢在代碼中實現  AddConverter("XXOO", typeof(XXOOPatternConverter));  嗎?

 

 

 

 第三步:定義自己框架的Log接口並實現它

沒啥可說的,看代碼吧。

LogMessage.cs   這個類其實就是寫了一個傳入的的自定義參數的實體類,你可以自己寫。不過最好是繼承這個類進行擴展。

using System;

namespace HY.Log
{
    /// <summary>
    /// 用於記錄日志信息
    /// </summary>
    [Serializable]
    public class LogMessage
    {
        /// <summary>
        /// 日志信息
        /// </summary>
        public string Message { get; set; }

    }
}

 

 

ILog.cs

using System;

namespace HY.Log
{
    public interface ILog
    {
        /// <summary>
        /// 寫入Debug日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        void Debug(string message, Exception exception = null);

        /// <summary>
        /// 寫入Debug日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        void Debug(object messageEntity, Exception exception = null);


        /// <summary>
        /// 寫入Info日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        void Info(string message, Exception exception = null);

        /// <summary>
        /// 寫入Info日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        void Info(object messageEntity, Exception exception = null);

        /// <summary>
        /// 寫入Warn日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        void Warn(string message, Exception exception = null);

        /// <summary>
        /// 寫入Warn日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        void Warn(object messageEntity, Exception exception = null);

        /// <summary>
        /// 寫入Error日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        void Error(string message, Exception exception = null);

        /// <summary>
        /// 寫入Error日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        void Error(object messageEntity, Exception exception = null);


        /// <summary>
        /// 寫入Fatal日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        void Fatal(string message, Exception exception = null);

        /// <summary>
        /// 寫入Fatal日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        void Fatal(object messageEntity, Exception exception = null);


    }
}

 

NormalLog.cs

using System;
using System.Collections.Generic;

namespace HY.Log
{
    public class NormalLog : ILog
    {
        #region private
        private static Dictionary<string, log4net.ILog> listILog = new Dictionary<string, log4net.ILog>();   //Log對象集合
        private log4net.ILog iLog;  //當前日志對象的實例
        #endregion

        #region 構造函數


        /// <summary>
        /// 構造函數,傳入Log4NET 的ILog對象
        /// </summary>
        /// <param name="logger"></param>
        public NormalLog(log4net.ILog logger)
        {
            string LoggerName = logger.Logger.Name;     //logger 配置節名稱
            if (!listILog.ContainsKey(LoggerName))
            {
                lock (listILog)
                {
                    if (!listILog.ContainsKey(LoggerName))
                    {
                        listILog.Add(LoggerName, logger);
                    }
                    else
                    {
                        listILog[LoggerName] = logger;
                    }
                }
            }
            else if (listILog[LoggerName] == null)
            {
                listILog[LoggerName] = logger;
            }
            iLog = listILog[LoggerName];
        }


        public NormalLog(string loggerName)
        {
            log4net.ILog logger = log4net.LogManager.GetLogger(loggerName);
            string LoggerName = logger.Logger.Name;     //logger 配置節名稱
            if (!listILog.ContainsKey(LoggerName))
            {
                listILog.Add(LoggerName, logger);
            }
            else if (listILog[LoggerName] == null)
            {
                listILog[LoggerName] = logger;
            }
            iLog = listILog[LoggerName];
        }

        #endregion

        #region 寫入日志

        /// <summary>
        /// 寫入Debug日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        public void Debug(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Debug(messageEntity, exception);
        }

        /// <summary>
        /// 寫入Debug日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        public void Debug(object messageEntity, Exception exception = null)
        {
            if (iLog.IsDebugEnabled)
            {
                if (exception != null)
                {
                    iLog.Debug(messageEntity, exception);
                }
                else
                {
                    iLog.Debug(messageEntity);
                }
            }
        }

        /// <summary>
        /// 寫入Info日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        public void Info(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Info(messageEntity, exception);
        }

        /// <summary>
        /// 寫入Info日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        public void Info(object messageEntity, Exception exception = null)
        {
            if (iLog.IsInfoEnabled)
            {
                if (exception != null)
                {
                    iLog.Info(messageEntity, exception);
                }
                else
                {
                    iLog.Info(messageEntity);
                }
            }
        }


        /// <summary>
        /// 寫入Warn日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        public void Warn(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Warn(messageEntity, exception);
        }


        /// <summary>
        /// 寫入Warn日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        public void Warn(object messageEntity, Exception exception = null)
        {
            if (iLog.IsWarnEnabled)
            {
                if (exception != null)
                {
                    iLog.Warn(messageEntity, exception);
                }
                else
                {
                    iLog.Warn(messageEntity);
                }
            }
        }



        /// <summary>
        /// 寫入Error日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        public void Error(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Error(messageEntity, exception);
        }

        /// <summary>
        /// 寫入Error日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        public void Error(object messageEntity, Exception exception = null)
        {
            if (iLog.IsErrorEnabled)
            {
                if (exception != null)
                {
                    iLog.Error(messageEntity, exception);
                }
                else
                {
                    iLog.Error(messageEntity);
                }
            }
        }

        /// <summary>
        /// 寫入Fatal日志,
        /// </summary>
        /// <param name="message">日志信息,占位符為 %Object{Message}</param>
        public void Fatal(string message, Exception exception = null)
        {
            LogMessage messageEntity = new LogMessage
            {
                Message = message
            };
            Fatal(messageEntity, exception);
        }

        /// <summary>
        /// 寫入Fatal日志
        /// </summary>
        /// <param name="messageEntity">日志實體信息, 占位符為 %Object{實體類的屬性名稱}</param>
        public void Fatal(object messageEntity, Exception exception = null)
        {
            if (iLog.IsFatalEnabled)
            {
                if (exception != null)
                {
                    iLog.Fatal(messageEntity, exception);
                }
                else
                {
                    iLog.Fatal(messageEntity);
                }
            }
        }
        #endregion

    }
}

 

  第四步:寫一下log模塊的支持方法(這裡有實現log4net配置和連接字符串共用一個配置的方法)

 

 LogManager.cs

這個類定義的了log4net模塊的初始化,數據庫連接設置……

using System;
using System.IO;
using log4net.Appender;
using log4net.Config;
using log4net.Repository.Hierarchy;

namespace HY.Log
{
    public class LogManager
    {

        /// <summary>
        /// 設置DB連接字符串
        /// </summary>
        /// <param name="conString">連接字符串</param>
        /// <param name="loggerName">loggerName</param>
        /// <param name="appenderName">appenderName</param>
        public static void ConfigConnection(string conString, string loggerName, string appenderName = "ADONetAppender")
        {
            try
            {
                Hierarchy h = log4net.LogManager.GetRepository() as Hierarchy;
                if (h != null)
                {
                    AdoNetAppender adoAppender = (AdoNetAppender)h.GetLogger(loggerName,
                        h.LoggerFactory).GetAppender(appenderName);
                    if (adoAppender != null)
                    {
                        adoAppender.ConnectionString = conString;
                        adoAppender.ActivateOptions();
                    }
                }

            }
            catch (NullReferenceException) { }
        }


        /// <summary>
        /// 初始化HY.Log,  Log配置文件需要寫到 Web.config  OR  App.config
        /// </summary>
        public static void Init()
        {
            XmlConfigurator.Configure();
        }

        /// <summary>
        /// 初始化HY.Log, 
        /// </summary>
        /// <param name="configFileName">制定Log配置文件的文件絕對路徑</param>
        public static void Init(string configFileName)
        {
            XmlConfigurator.Configure(new FileInfo(configFileName));
        }



        /// <summary>
        /// 檢索Logger名稱返回日志處理接口
        /// </summary>
        /// <param name="name">Logger名稱</param>
        /// <returns>日志接口</returns>
        public static ILog GetLogger(string name)
        {
            var log4Logger = log4net.LogManager.GetLogger(name);
            return new NormalLog(log4Logger);
        }


    }
}

 

 第五步:如何使用HY.Log.DLL

上面的代碼大家看到了,已經可以成功編譯一個dll 文件了。


先來編輯一個log4net配置文件

<?xml version="1.0"?>
<configuration>
  <!--Log4net Begin-->
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <log4net>
    <!--Log4net Begin,程序運行異常記錄-->

    <logger name="LogInfoDB">
      <level value="ALL" />
      <appender-ref ref="ADONetAppender" />
    </logger>
    <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
      <bufferSize value="1" />
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <!--<connectionString value="Data Source=127.0.0.1;Database=test;uid=sa;pwd=test;Max Pool Size=300;Connect Timeout=15;" />-->
      <commandText value="INSERT INTO HY_Log ([LogType],[ModelName],[Message],[Exception],[IP],[Log_Date],[UserID]) VALUES (@LogType,@ModelName, @Message, @Exception, @IP,@Log_Date,@UserID)" />
      <parameter>
        <parameterName value="@LogType" />
        <dbType value="String" />
        <size value="20" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{LogType}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@ModelName" />
        <dbType value="String" />
        <size value="110" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{ModelName}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Message" />
        <dbType value="String" />
        <size value="2000" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{Message}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Exception" />
        <dbType value="String" />
        <size value="8000" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{Exception}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@IP" />
        <dbType value="String" />
        <size value="20" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%ClientIP" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Log_Date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@UserID" />
        <dbType value="String" />
        <size value="100" />
        <layout type="HY.Log.CustomLayout">
          <conversionPattern value="%Object{UserID}" />
        </layout>
      </parameter>
    </appender>

  </log4net>
  <!--Log4net End-->
</configuration>


<!--%m(message):輸出的日志消息,如ILog.Debug(…)輸出的一條消息
      %n(new line):換行
      %d(datetime):輸出當前語句運行的時刻
      %r(run time):輸出程序從運行到執行到當前語句時消耗的毫秒數
      %t(thread id):當前語句所在的線程ID
      %p(priority): 日志的當前優先級別,即DEBUG、INFO、WARN…等
      %c(class):當前日志對象的名稱,例如:
      %f(file):輸出語句所在的文件名。
      %l(line):輸出語句所在的行號。-->

 上面的配置文件是一個寫入DB的配置

請注意如下配置節:

<layout type="HY.Log.CustomLayout">
<conversionPattern value="%Object{Exception}" />
<conversionPattern value="%Object{LogType}" />
<conversionPattern value="%ClientIP" />
這便是采用了自定義配置。


創建HY.ILog對象
public static ILog ilog = null;

HY.Log.LogManager.Init(HttpContext.Current.Server.MapPath(@"~/Config/log4net.config"));//加載配置文件
HY.Log.LogManager.ConfigConnection(ConfigurationManager.ConnectionStrings["Connection"].ToString(), "LogInfoDB");//修改連接字符串
ilog = LogManager.GetLogger("LogInfoText");     //獲取Ilog對象 這裡可以采用單例模式。代碼就不貼了,


自定義實體類:
 [Serializable]
    public class LogEntity
    {
        /// <summary>
        /// 日志類型
        /// </summary>
        public LogType LogType { get; set; }

        /// <summary>
        /// 模塊名稱
        /// </summary>
        public string ModelName { get; set; }

        /// <summary>
        /// 信息
        /// </summary>
        public new string Message { get; set; }

        /// <summary>
        /// 異常信息
        /// </summary>
        public string Exception { get; set; }

        public string UserID { get; set; }

 


LogEntity loginfo = new LogEntity();
loginfo.ModelName = "ModelName";
           loginfo.Message = "Message";
           loginfo.Exception = "Exception";
           loginfo.UserID = "UserID";
           loginfo.LogType = "LogType.Business";
ilog.Error(loginfo,ex);
 
 到這裡就已經完了。  關於使用的代碼比較粗糙,這塊就需要根據你程序的具體需求來實現了。這裡點到為止。  因為後續我們將會采用spring.net來注入。 將在後續的文章介紹。


各位如果有更好的建立請給我留言, 請各位不吝賜教。
 

 

相關文章:

搭建一套自己實用的.net架構(1)【概述】

搭建一套自己實用的.net架構(2)【日志模塊-log4net】

搭建一套自己實用的.net架構(3)【ORM-Dapper+DapperExtensions】

搭建一套自己實用的.net架構(4)【CodeBuilder-RazorEngine】

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved