個人操做系統爲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