个人操做系统为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