我的操作系统为Win7旗舰版,.NET版本为4.5,log4net版本为1.2.15,Oracle版本为11g。
使用log4net建立一个最简单的DEMO,可以参考我的上一篇博客:
http://my.oschina.net/Tsybius2014/blog/687750
log4net支持将日志打印到数据库中,将日志中指定的内容打印到数据库中特定字段的方法有多种,本文选取一种较为灵活的方式,即继承ILog接口建立子接口。
首先在Oracle数据库中建立一张表,建表SQL如下:
CREATE TABLE PROGRAM_LOG (
DATETIME TIMESTAMP(3),
THREAD VARCHAR2(255),
LOG_LEVEL VARCHAR2(255),
LOGGER VARCHAR2(255),
SYS_CODE VARCHAR2(10),
MESSAGE VARCHAR2(4000)
);
我建立的工程结构如下:
其中,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>
这里要说明一下:
1、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工具查看。
2、 连接Oracle数据库需要手动添加引用 System.Data.OracleClient,数据库连接字符串connectionString就使用ADO.NET正常连接Oracle数据库时使用的连接字符串即可。
3、模块代码(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
来源:oschina
链接:https://my.oschina.net/u/1425762/blog/687992