log4net:添加自定義字段並將日誌存儲到Oracle11g數據庫中

個人操做系統爲Win7旗艦版,.NET版本爲4.5,log4net版本爲1.2.15,Oracle版本爲11g。html

使用log4net創建一個最簡單的DEMO,能夠參考個人上一篇博客:sql

http://my.oschina.net/Tsybius2014/blog/687750數據庫

log4net支持將日誌打印到數據庫中,將日誌中指定的內容打印到數據庫中特定字段的方法有多種,本文選取一種較爲靈活的方式,即繼承ILog接口創建子接口。apache

首先在Oracle數據庫中創建一張表,建表SQL以下:app

CREATE TABLE PROGRAM_LOG (
    DATETIME TIMESTAMP(3),
    THREAD VARCHAR2(255),
    LOG_LEVEL VARCHAR2(255),
    LOGGER VARCHAR2(255),
    SYS_CODE VARCHAR2(10),
    MESSAGE VARCHAR2(4000)
);

我創建的工程結構以下:dom

其中,log4net.config中保存了Appender相關配置函數

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
  </configSections>
  <log4net>
    <!--數據庫存儲日誌-->
    <appender name="ADONetAppender_Oracle" type="log4net.Appender.AdoNetAppender">
      <!--dll文件簽名-->
      <connectionType value="System.Data.OracleClient.OracleConnection, System.Data.OracleClient, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
      <!--數據庫鏈接字符串-->
      <connectionString value="Data Source=orcl;User Id=xxx;Password=xxx;" />
      <!--插入用SQL語句-->
      <commandText value="INSERT INTO PROGRAM_LOG (DATETIME, THREAD, LOG_LEVEL, LOGGER, SYS_CODE, MESSAGE) VALUES (:datetime, :thread, :log_level, :logger, :sys_code, :message)" />
      <bufferSize value="1" />
      <!--時間戳-->
      <parameter>
        <parameterName value=":datetime" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <!--線程號-->
      <parameter>
          <parameterName value=":thread" />
          <dbType value="String" />
          <size value="255" />
          <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%thread" />
          </layout>
      </parameter>
      <!--日誌等級-->
      <parameter>
          <parameterName value=":log_level" />
          <dbType value="String" />
          <size value="50" />
          <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%level" />
          </layout>
      </parameter>
      <!--類名-->
      <parameter>
          <parameterName value=":logger" />
          <dbType value="String" />
          <size value="255" />
          <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%logger" />
          </layout>
      </parameter>
      <!--模塊代碼-->
      <parameter>
        <parameterName value=":sys_code" />
        <dbType value="String" />
        <size value="10" />
        <layout type="log4net.Layout.PatternLayout" >
        <param name="ConversionPattern" value="%property{SysCode}"/>
        </layout>
      </parameter>
      <!--日誌信息-->
      <parameter>
        <parameterName value=":message" />
        <dbType value="String" />
        <size value="1024" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%message" />
        </layout>
      </parameter>
    </appender>
    <root>
      <appender-ref ref="ADONetAppender_Oracle" />
    </root>
  </log4net>
</configuration>

這裏要說明一下:工具

一、dll文件的簽名必定要寫對。個人電腦中用的是「System.Data.OracleClient.OracleConnection, System.Data.OracleClient, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089」,Version以VS中引用屬性中顯示的爲準(注意不是在資源管理器裏找到dll文件後查看屬性界面看到的版本,那是.NET的版本,如4.0.30319.1),PublicKeyToken通常都是B77A5C561934E089,若是要確承認以在VS開發者命令行中使用SN工具查看。this

二、 鏈接Oracle數據庫須要手動添加引用 System.Data.OracleClient,數據庫鏈接字符串connectionString就使用ADO.NET正常鏈接Oracle數據庫時使用的鏈接字符串便可。spa

三、模塊代碼(SysCode)是我自定義的字段。

創建IEnhancedLog接口,繼承自ILog接口:

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

namespace Log4NetTest
{
    public interface IEnhancedLog : ILog
    {
        void Debug(string sysCode, object message);
        void Debug(string sysCode, object message, Exception t);

        void Info(string sysCode, object message);
        void Info(string sysCode, object message, Exception t);

        void Warn(string sysCode, object message);
        void Warn(string sysCode, object message, Exception t);

        void Error(string sysCode, object message);
        void Error(string sysCode, object message, Exception t);

        void Fatal(string sysCode, object message);
        void Fatal(string sysCode, object message, Exception t);
    }
}

創建EnhancedLogImpl實現類,繼承自LogImpl類和IEnhancedLog接口:

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

namespace Log4NetTest
{
    public class EnhancedLogImpl : LogImpl, IEnhancedLog
    {
        private readonly static Type ThisDeclaringType = typeof(EnhancedLogImpl);
        
        public EnhancedLogImpl(ILogger logger)
            : base(logger)
        {
        }

        public void Debug(string sysCode, object message)
        {
            Debug(sysCode, message, null);
        }

        public void Debug(string sysCode, object message, System.Exception t)
        {
            if (this.IsDebugEnabled)
            {
                LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Debug, message, t);
                loggingEvent.Properties["SysCode"] = sysCode;
                Logger.Log(loggingEvent);
            }
        }

        public void Info(string sysCode, object message)
        {
            Info(sysCode, message, null);
        }

        public void Info(string sysCode, object message, System.Exception t)
        {
            if (this.IsInfoEnabled)
            {
                LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Info, message, t);
                loggingEvent.Properties["SysCode"] = sysCode;
                Logger.Log(loggingEvent);
            }
        }

        public void Warn(string sysCode, object message)
        {
            Warn(sysCode, message, null);
        }

        public void Warn(string sysCode, object message, System.Exception t)
        {
            if (this.IsWarnEnabled)
            {
                LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Warn, message, t);
                loggingEvent.Properties["SysCode"] = sysCode;
                Logger.Log(loggingEvent);
            }
        }

        public void Error(string sysCode, object message)
        {
            Error(sysCode, message, null);
        }

        public void Error(string sysCode, object message, System.Exception t)
        {
            if (this.IsErrorEnabled)
            {
                LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Error, message, t);
                loggingEvent.Properties["SysCode"] = sysCode;
                Logger.Log(loggingEvent);
            }
        }

        public void Fatal(string sysCode, object message)
        {
            Fatal(sysCode, null);
        }

        public void Fatal(string sysCode, object message, System.Exception t)
        {
            if (this.IsFatalEnabled)
            {
                LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Fatal, message, t);
                loggingEvent.Properties["SysCode"] = sysCode;
                Logger.Log(loggingEvent);
            }
        }

    }
}

創建EnhancedLogManager類,用於獲取logger:

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

namespace Log4NetTest
{
    public class EnhancedLogManager
    {
        private static readonly WrapperMap s_wrapperMap = new WrapperMap(new WrapperCreationHandler(WrapperCreationHandler));

        private EnhancedLogManager() { }

        public static IEnhancedLog Exists(string name)
        {
            return Exists(Assembly.GetCallingAssembly(), name);
        }

        public static IEnhancedLog Exists(string domain, string name)
        {
            return WrapLogger(LoggerManager.Exists(domain, name));
        }

        public static IEnhancedLog Exists(Assembly assembly, string name)
        {
            return WrapLogger(LoggerManager.Exists(assembly, name));
        }

        public static IEnhancedLog[] GetCurrentLoggers()
        {
            return GetCurrentLoggers(Assembly.GetCallingAssembly());
        }

        public static IEnhancedLog[] GetCurrentLoggers(string domain)
        {
            return WrapLoggers(LoggerManager.GetCurrentLoggers(domain));
        }

        public static IEnhancedLog[] GetCurrentLoggers(Assembly assembly)
        {
            return WrapLoggers(LoggerManager.GetCurrentLoggers(assembly));
        }

        public static IEnhancedLog GetLogger(string name)
        {
            return GetLogger(Assembly.GetCallingAssembly(), name);
        }

        public static IEnhancedLog GetLogger(string domain, string name)
        {
            return WrapLogger(LoggerManager.GetLogger(domain, name));
        }

        public static IEnhancedLog GetLogger(Assembly assembly, string name)
        {
            return WrapLogger(LoggerManager.GetLogger(assembly, name));
        }

        public static IEnhancedLog GetLogger(Type type)
        {
            return GetLogger(Assembly.GetCallingAssembly(), type.FullName);
        }

        public static IEnhancedLog GetLogger(string domain, Type type)
        {
            return WrapLogger(LoggerManager.GetLogger(domain, type));
        }

        public static IEnhancedLog GetLogger(Assembly assembly, Type type)
        {
            return WrapLogger(LoggerManager.GetLogger(assembly, type));
        }

        private static IEnhancedLog WrapLogger(ILogger logger)
        {
            return (IEnhancedLog)s_wrapperMap.GetWrapper(logger);
        }

        private static IEnhancedLog[] WrapLoggers(ILogger[] loggers)
        {
            IEnhancedLog[] results = new IEnhancedLog[loggers.Length];
            for (int i = 0; i < loggers.Length; i++)
            {
                results[i] = WrapLogger(loggers[i]);
            }
            return results;
        }

        private static ILoggerWrapper WrapperCreationHandler(ILogger logger)
        {
            return new EnhancedLogImpl(logger);
        }
    }
}

主函數代碼以下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using log4net;
using log4net.Config;
using System.Data.OracleClient;

namespace Log4NetTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //加載log4net配置
            FileInfo configFile = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config");
            XmlConfigurator.ConfigureAndWatch(configFile);

            IEnhancedLog logger = EnhancedLogManager.GetLogger(typeof(Program));
            logger.Debug("sys1", "調試類型日誌");
            logger.Info("sys1", "通常類型日誌");
            logger.Warn("sys2", "警告類型日誌");
            logger.Error("sys3", "錯誤類型日誌");
            //logger.Fatal("sys2", "致命錯誤日誌"); //會致使StackOverFlow,緣由未知

            try
            {
                int a = 0;
                int b = 0;
                int i = a / b;
            }
            catch (Exception ex)
            {
                logger.Error("sys3", ex);
            }

            Console.WriteLine("日誌輸出完畢");
            Console.Read();
        }
    }
}

程序執行結果以下:

這段代碼有一個問題到如今我也沒找到緣由,就是調用logger.Fatal時總會提示StackOverFlow異常~~~╮(╯▽╰)╭

剛開始調試log4net有一個比較痛苦的地方,就是log4net的日誌並不會打印到控制檯上,在出現問題後總會讓人感受丈二和尚摸不着頭腦。不事後來我發現,在App.config文件中加入這句話就能夠了:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!--↓↓↓加入這句話↓↓↓-->
    <add key="log4net.Internal.Debug" value="true "/>
  </appSettings>
  <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

添加了該項配置後,執行上面程序時,控制檯中打印的log4net運行日誌以下:

log4net: log4net assembly [log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a]. Loaded from [D:\MyPrograms\Log4NetTest\Log4NetTest\bin\
Debug\log4net.dll]. (.NET Runtime [4.0.30319.18444] on Microsoft Windows NT 6.1.7601 Service Pack 1)
log4net: defaultRepositoryType [log4net.Repository.Hierarchy.Hierarchy]
log4net: Creating repository for assembly [Log4NetTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]
log4net: Assembly [Log4NetTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null] Loaded From [D:\MyPrograms\Log4NetTest\Log4NetTest\bin\Debug\Log4NetTest.
exe]
log4net: Assembly [Log4NetTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null] does not have a RepositoryAttribute specified.
log4net: Assembly [Log4NetTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null] using repository [log4net-default-repository] and repository type [log4ne
t.Repository.Hierarchy.Hierarchy]
log4net: Creating repository [log4net-default-repository] using type [log4net.Repository.Hierarchy.Hierarchy]
log4net: configuring repository [log4net-default-repository] using file [D:\MyPrograms\Log4NetTest\Log4NetTest\bin\Debug\log4net.config] watching for file updat
es
log4net: configuring repository [log4net-default-repository] using file [D:\MyPrograms\Log4NetTest\Log4NetTest\bin\Debug\log4net.config]
log4net: configuring repository [log4net-default-repository] using stream
log4net: loading XML configuration
log4net: Configuring Repository [log4net-default-repository]
log4net: Configuration update mode [Merge].
log4net: Loading Appender [ADONetAppender_Oracle] type: [log4net.Appender.AdoNetAppender]
log4net: Setting Property [ConnectionType] to String value [System.Data.OracleClient.OracleConnection, System.Data.OracleClient, Version=4.0.0.0, Culture=neutra
l, PublicKeyToken=B77A5C561934E089]
log4net: Setting Property [ConnectionString] to String value [Data Source=orcl;User Id=XXXX;Password=XXXX;]
log4net: Setting Property [CommandText] to String value [INSERT INTO PROGRAM_LOG (DATETIME, THREAD, LOG_LEVEL, LOGGER, SYS_CODE, MESSAGE) VALUES (:datetime, :th
read, :log_level, :logger, :sys_code, :message)]
log4net: Setting Property [BufferSize] to Int32 value [1]
log4net: Setting Property [ParameterName] to String value [:datetime]
log4net: Setting Property [DbType] to DbType value [DateTime]
log4net: Setting Property [Layout] to object [log4net.Layout.RawTimeStampLayout]

log4net: Setting Collection Property [AddParameter] to object [log4net.Appender.AdoNetAppenderParameter]
log4net: Setting Property [ParameterName] to String value [:thread]
log4net: Setting Property [DbType] to DbType value [String]
log4net: Setting Property [Size] to Int32 value [255]
log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [ConversionPattern] to String value [%thread]
log4net: Converter [thread] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [Layout] to object [log4net.Layout.Layout2RawLayoutAdapter]
log4net: Setting Collection Property [AddParameter] to object [log4net.Appender.AdoNetAppenderParameter]
log4net: Setting Property [ParameterName] to String value [:log_level]
log4net: Setting Property [DbType] to DbType value [String]
log4net: Setting Property [Size] to Int32 value [50]
log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [ConversionPattern] to String value [%level]
log4net: Converter [level] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [Layout] to object [log4net.Layout.Layout2RawLayoutAdapter]
log4net: Setting Collection Property [AddParameter] to object [log4net.Appender.AdoNetAppenderParameter]
log4net: Setting Property [ParameterName] to String value [:logger]
log4net: Setting Property [DbType] to DbType value [String]
log4net: Setting Property [Size] to Int32 value [255]
log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [ConversionPattern] to String value [%logger]
log4net: Converter [logger] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [Layout] to object [log4net.Layout.Layout2RawLayoutAdapter]
log4net: Setting Collection Property [AddParameter] to object [log4net.Appender.AdoNetAppenderParameter]
log4net: Setting Property [ParameterName] to String value [:sys_code]
log4net: Setting Property [DbType] to DbType value [String]
log4net: Setting Property [Size] to Int32 value [10]
log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [ConversionPattern] to String value [%property{SysCode}]
log4net: Converter [property] Option [SysCode] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [Layout] to object [log4net.Layout.Layout2RawLayoutAdapter]
log4net: Setting Collection Property [AddParameter] to object [log4net.Appender.AdoNetAppenderParameter]
log4net: Setting Property [ParameterName] to String value [:message]
log4net: Setting Property [DbType] to DbType value [String]
log4net: Setting Property [Size] to Int32 value [1024]
log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [ConversionPattern] to String value [%message]
log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False]
log4net: Setting Property [Layout] to object [log4net.Layout.Layout2RawLayoutAdapter]
log4net: Setting Collection Property [AddParameter] to object [log4net.Appender.AdoNetAppenderParameter]
log4net: Created Appender [ADONetAppender_Oracle]
log4net: Adding appender named [ADONetAppender_Oracle] to logger [root].
log4net: Hierarchy Threshold []
日誌輸出完畢

參考資料:

擴展Log4Net中的ILog實現自定義日誌字段

http://www.cnblogs.com/hb_cattle/articles/1560778.html

Apache log4net™ Config Examples

http://logging.apache.org/log4net/release/config-examples.html

END

相關文章
相關標籤/搜索