type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
二是节的具体配置,这是下面要重点说明的。
4.1.1
所有的配置都要在元素里定义。
支持的属性:
debug |
可选,取值是true或false,默认是false。设置为true,开启log4net的内部调试。 |
update |
可选,取值是Merge(合并)或Overwrite(覆盖),默认值是Merge。设置为Overwrite,在提交配置的时候会重置已经配置过的库。 |
threshold |
可选,取值是repository(库)中注册的level,默认值是ALL。 |
支持的子元素:
appender |
0或多个 |
logger |
0或多个 |
renderer |
0或多个 |
root |
最多一个 |
param |
0或多个 |
4.1.2
实际上就是一个根logger,所有其它logger都默认继承它,如果配置文件里没有显式定义,则框架使用根日志中定义的属性。root元素没有属性。
支持的子元素:
appender-ref |
0个或多个,要引用的appender的名字。 |
level |
最多一个。 只有在这个级别或之上的事件才会被记录。 |
param |
0个或多个, 设置一些参数。 |
4.1.3
支持的属性:
name |
必须的,logger的名称 |
additivity |
可选,取值是true或false,默认值是true。设置为false时将阻止父logger中的appender。 |
支持的子元素:
appender-ref |
0个或多个,要引用的appender的名字。 |
level |
最多一个。 只有在这个级别或之上的事件才会被记录。 |
param |
0个或多个, 设置一些参数。 |
4.1.4
定义日志的输出方式,只能作为 log4net 的子元素。name属性必须唯一,type属性必须指定。
支持的属性:
name |
必须的,Appender对象的名称 |
type |
必须的,Appender对象的输出类型 |
支持的子元素:
appender-ref |
0个或多个,允许此appender引用其他appender,并不是所以appender类型都支持。 |
filter |
0个或多个,定义此app使用的过滤器。 |
layout |
最多一个。定义appender使用的输出格式。 |
param |
0个或多个, 设置Appender类中对应的属性的值。 |
实际上所能包含的子元素远不止上面4个。
4.1.5
布局,只能作为的子元素。
支持的属性:
支持的子元素:
4.1.6
过滤器,只能作为的子元素。
支持的属性:
支持的子元素:
4.1.7
元素可以是任何元素的子元素。
支持的属性:
name |
必须的,取值是父对象的参数名。 |
value |
可选的,value和type中,必须有一个属性被指定。value是一个能被转化为参数值的字符串。 |
type |
可选的,value和type中,必须有一个属性被指定。type是一个类型名,如果type不是在log4net程序集中定义的,就需要使用全名。 |
支持的子元素:
4.2 配置
在配置文件中至少有一个,也可以有多个,有些类型还可以引用其他类型,具体参数可参见上表。
下面只对写入回滚文件与输出到数据库(这里使用SQL数据库)配置体会说一下,其他配置可参考官方网站:http://logging.apache.org/log4net/release/config-examples.html
4.2.1写入回滚文件
PatternLayout的自定义布局,TGLog.ExpandLayout2
为命名空间。%property{Operator}、%property{Action}是自定义的输出-->
value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 记录类:%logger 操作者ID:%property{Operator} 操作类型:%property{Action}%n 当前机器名:%property%n当前机器名及登录用户:%username %n 记录位置:%location%n 消息描述:%property{Message}%n 异常:%exception%n 消息:%message%newline%n%n" />
注意这些配置属性有些是可选的,如果需要,一定要写正确,否则要么输出的不是自己想要的结果,要么干脆不输出任何信息。
4.2.1写入SQL数据库
需要在相应的数据库中准备好一张表,创建语句如下:
CREATE TABLE [Log] (
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[Date] [datetime] NOT NULL ,
[Thread] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[Level] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[Logger] [varchar] (200) COLLATE Chinese_PRC_CI_AS NULL ,
[Operator] [int] NULL ,
[Message] [text] COLLATE Chinese_PRC_CI_AS NULL ,
[ActionType] [int] NULL ,
[Operand] [varchar] (300) COLLATE Chinese_PRC_CI_AS NULL ,
[IP] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
[MachineName] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[Browser] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[Location] [text] COLLATE Chinese_PRC_CI_AS NULL ,
[Exception] [text] COLLATE Chinese_PRC_CI_AS NULL
)
-->
RawTimeStampLayout为默认的时间输出格式 -->
RawTimeStampLayout" />
PatternLayout">
PatternLayout">
PatternLayout">
PatternLayout">
注意:
向表中输出的字段不能多于数据表本身字段,而反之则可以,但这些多余字段一定使其可以为空,否则便写不到数据库;
输出字段的类型一定是对应数据表字段数据类型可以隐式转换的,而且长度也不能超过,否则也不能写入;
数据表字段设置尽量可以为空,这样可以避免一条日志记录存在空数据导致后面的日志都记录不了。
4.3的配置
在配置文件中的配置好了输出的介质,格式,过滤方式,还要定义日志对象。
在框架的体系里,所有的日志对象都是根日志(root logger)的后代。 因此如果一个日志对象没有在配置文件里显式定义,则框架使用根日志中定义的属性。在标签里,可以定义level级别值和Appender的列表。如果没有定义LEVEL的值,则缺省为DEBUG。可以通过标签定义日志对象使用的Appender对象。声明了在其他地方定义的Appender对象的一个引用。在一个logger对象中的设置会覆盖根日志的设置。而对Appender属性来说,子日志对象则会继承父日志对象的Appender列表。这种缺省的行为方式也可以通过显式地设定标签的additivity属性为false而改变。
不显式申明时使用默认的配置。我觉得在使用时不定义,自定义多个,在程序中记录日志时直接使用的name来查找相应的,这样更灵活一些。例如:
4.4关联配置文件
log4net默认关联的是应用程序的配置文件App.config(BS程序是Web.config),可以使用程序集自定义属性来进行设置。下面来介绍一下这个自定义属性:
log4net.Config.XmlConifguratorAttribute。
XmlConfiguratorAttribute有3个属性:
ConfigFile: 配置文件的名字,文件路径相对于应用程序目录
(AppDomain.CurrentDomain.BaseDirectory)。ConfigFile属性不能和ConfigFileExtension属性一起使用。
ConfigFileExtension: 配置文件的扩展名,文件路径相对于应用程序的目录。ConfigFileExtension属性不能和ConfigFile属性一起使用。
Watch: 如果将Watch属性设置为true,就会监视配置文件。当配置文件发生变化的时候,就会重新加载。
如果ConfigFile和ConfigFileExtension都没有设置,则使用应用程序的配置文件App.config(Web.config)。
可以在项目的AssemblyInfo.cs文件里添加以下的语句:
//监视默认的配置文件,App.exe.config
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
//监视配置文件,App.exe.log4net。
[assembly: log4net. Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)]
//使用配置文件log4net.config,不监视改变。注意log4net.config文件的目录,BS程序在站点目录//下,CS则在应用程序启动目录下,如调试时在/bin/Debug下,一般将文件属性的文件输出目录调为//始终复制即可
[assembly: log4net. Config.XmlConfigurator(ConfigFile = "log4net.config")]
//使用配置文件log4net.config,不监视改变
[assembly: log4net. Config.XmlConfigurator()]
也可以在Global.asax的Application_Start里或者是Program.cs中的Main方法中添加,注意这里一定是绝对路径,如下所示:
//这是在BS程序下,使用自定义的配置文件log4net.xml,使用Server.MapPath("~") + //@"/log4net.xml”来取得路径。/log4net.xml为相对于站点的路径
// ConfigureAndWatch()相当于Configure(Watch = true)
log4net.Config.XmlConfigurator.ConfigureAndWatch(
new System.IO.FileInfo(Server.MapPath("~") + @"/log4net.xml"));
//这是在CS程序下,可以用以下方法获得:
string assemblyFilePath = Assembly.GetExecutingAssembly().Location;
string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath);
string configFilePath = assemblyDirPath + " //log4net.xml";
log4net.Config.XmlConfigurator.ConfigureAndWatch(
new FileInfo(configFilePath));
或直接使用绝对路径:
//使用自定义的配置文件,直接绝对路径为:c:/log4net.config
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(@"c:/log4net.config"));
5、如何记录日志
Log4net使用很方便,先申明一个封装类ILog 的对象,如下:
log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");
其中"ReflectionLayout"便是我们自定义的日志对象的name的值。
对应5个日志输出级别,log有5 个方法,每个方法都有两个重载,使用如下:
try
{
log.Debug("这是一个测试!");
}
catch(Exception ec)
{
log.Error("出现错误!", ec);
}
如果我们需要输出的消息是要区别开来,不按一个字符串全部输出,就需要进行一些扩展了。
6、Log4net的简单扩展
6.1通过重写布局Layout输出传入的 message对象的属性
6.1.1重写Layout类
通过继承log4net.Layout.PatternLayout类,使用log4net.Core.LoggingEvent类的方法得到了要输出的message类的名称,然后通过反射得到各个属性的值,使用PatternLayout类AddConverter方法传入得到的值。这里注意要引用用到的类的命名空间。
代码见附注8.2。
6.1.2配置相应的配置文件
配置文件其他地方不用改动,只是需要改动中的。例如:
value="记录时间:%date 操作者ID:%property{Operator}
操作类型:%property{Action}%n 消息描述:%property{Message}%n 异常:%exception%n " />
其中的type由原来的log4net.Layout.PatternLayout换为自定义的TGLog.ExpandLayout2.ReflectionLayout(TGLog.ExpandLayout2为命名空间)。%property{Operator}输出的即为message类对象的属性Operator的值。数据库配置同样,相应的字段如果是自定义的,则输出选用自定义的。例:
6.1.3程序中如何使用
和一般使用方法基本相同,只是传入的参数是一个自定义的类,类的属性和配置文件中所有的%property{属性}是一致的,即%property{属性}在输出的时候就查找传入message类中有无对应的属性,如果有就输出值,没有则输出null。例:
log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");
try
{
log.Debug(new LogMessage(
1,
"操作对象:0",
(int)TGLog.ActionType.Other,
"这是四个参数测试")
);
}
catch(Exception ec)
{
log.Error(new LogMessage(
1,
"操作对象:0",
(int)TGLog.ActionType.Other,
"这是全部参数测试",
"192.168.1.1",
"MyComputer",
"Maxthon(MyIE2)Fans"),
ec
);
}
LogMessage的全部属性的构造方法如下:
public LogMessage(
int operatorID,
string operand,
int ActionType,
string message,
string ip,
string machineName,
string browser
)
{
this.ActionType = ActionType;
this.Operator = operatorID;
this.Message = message;
this.Operand = operand;
this.IP = ip;
this.Browser = browser;
this.MachineName = machineName;
}
6.2通过重新实现ILog接口来增加输入的参数
6.2.1重写LogImpl,LogManager类及实现ILog接口
这种方式是通过构造一个名为IMyLog接口,是继承Ilog接口而来,然后分别在MyLogImpl,MyLogManager重新实现IMyLog接口,增加了每种方法的参数。MyLogImpl,MyLogManager分别继承LogImpl,LogManager而来。
代码分别见8.3、8.4、8.5:
6.2.2配置相应的配置文件
配置文件其他地方不用改动,只是需要改动中的元素name为ConversionPattern的value中输出格式。例如:
PatternLayout ">
value="记录时间:%date 操作者ID:%property{Operator}
操作类型:%property{Action}%n 消息描述:%property{Message}%n 异常:%exception%n " />
%property{参数}中的参数在MyLogImpl类中定义,如语句:
loggingEvent.Properties["Operator"] = operatorID;
就定义了Operator输出参数,即%property{Operator}输出的即为IMyLog中的参数operatorID的值。
数据库配置同样。例:
PatternLayout ">
6.2.3程序中如何使用
先引用IMyLog ,MyLogManager所在的命名空间,创建一个IMyLog对象,myLog的5 个方法,每个方法都有四个重载,增加了多参数的重载。例:
IMyLog myLog = MyLogManager.GetLogger("ExpandILog");
try
{
myLog.Debug("这是一个参数重载测试!");
}
catch(Exception ec)
{
log.Error(
1,
"操作对象:0",
(int)TGLog.ActionType.Other,
"这是全部参数测试",
"192.168.1.1",
"MyComputer",
"Maxthon(MyIE2)Fans",
ec
);
}
7、总结
Log4net 功能很多,这里只是对已经尝试用过的功能总结一下,普通写日志已经足够。需要注意的是:
1. Log4net本身也有一些缺陷,比如一个记录引起了log4net本身的异常,就会使后面的日志无法记录下来,尤其是在写入数据库时。例如使用6.1扩展后,int型的属性在的元素设置不为1时,时,就不能输出到数据库,而则没任何问题。
2. Log4net本身出现了异常,比如配置文件出现错误,有些日志输出方式会记录下这些异常,例如应用程序控制台;有些则不会输出这些错误,如数据库与文件。
3. 扩展时也会留下一些问题。例如在使用6.1扩展输出字段时就会出现,在log.debug(object message)中,如果message是一个自定义的类,属性与配置文件中输出设置也一致,构造函数时也只构造一个参数的实例,写文件与写数据库都成功,而将message按没有扩展的方式直接传入一个字符串,即log.debug(“信息内容”)使用则只能写入文件,而数据库则没写入。自定义的Layout 就是继承默认的PatternLayout,本来不应该出错,但出现了问题。原因分析是自定义的message类有类型为int的属性,作为一个对象传入时在默认值0,而直接使用字符串则int型的字段得不到默认值,引发异常。所以建议在有扩展存在时,最好多设几个,区分清楚,按照统一的形式记录日志,不要混合使用。
4. 配置文件的设置一定要准确,在一点不正确就会导致日志不能正常输出,所以在配置时先从最简单的开始,同时输出方式选择一种能输出log4net本身异常的方式,成功后一点一点加在新配置,这样出错了也容易找到那个地方配置有问题。
5. log4net扩展性很强,几乎所有的组件都可以重写,在配置文件中配置好就可以使用。
8、附注:
8.1PatterLayout格式化字符表
转换字符 |
效果 |
a |
等价于appdomain |
appdomain |
引发日志事件的应用程序域的友好名称。(使用中一般是可执行文件的名字。) |
c |
等价于 logger |
C |
等价于 type |
class |
等价于 type |
d |
等价于 date |
date |
发生日志事件的本地时间。 使用 DE>%utcdate 输出UTC时间。date后面还可以跟一个日期格式,用大括号括起来。DE>例如:%date{HH:mm:ss,fff}或者%date{dd MMM yyyy HH:mm:ss,fff}。如果date后面什么也不跟,将使用ISO8601 格式 。 日期格式和.Net中DateTime类的ToString方法中使用的格式是一样。 另外log4net还有3个自己的格式Formatter。 它们是 "ABSOLUTE", "DATE"和"ISO8601"分别代表 AbsoluteTimeDateFormatter, DateTimeDateFormatter和Iso8601DateFormatter。例如:%date{ISO8601}或%date{ABSOLUTE}。 它们的性能要好于ToString。 |
exception |
异常信息 日志事件中必须存了一个异常对象,如果日志事件不包含没有异常对象,将什么也不输出。异常输出完毕后会跟一个换行。一般会在输出异常前加一个换行,并将异常放在最后。 |
F |
等价于 file |
file |
发生日志请求的源代码文件的名字。 警告:只在调试的时候有效。调用本地信息会影响性能。 |
identity |
当前活动用户的名字(Principal.Identity.Name). 警告:会影响性能。(我测试的时候%identity返回都是空的。) |
l |
等价于 location |
L |
等价于 line |
location |
引发日志事件的方法(包括命名空间和类名),以及所在的源文件和行号。 警告:会影响性能。没有pdb文件的话,只有方法名,没有源文件名和行号。 |
level |
日志事件等级 |
line |
引发日志事件的行号 警告:会影响性能。 |
logger |
记录日志事件的Logger对象的名字。 可以使用精度说明符控制Logger的名字的输出层级,默认输出全名。 注意,精度符的控制是从右开始的。例如:logger 名为 "a.b.c", 输出模型为%logger{2} ,将输出"b.c"。 |
m |
等价于 message |
M |
等价于 method |
message |
由应用程序提供给日志事件的消息。 |
mdc |
MDC (旧为:ThreadContext.Properties) 现在是事件属性的一部分。 保留它是为了兼容性,它等价于 property。 |
method |
发生日志请求的方法名(只有方法名而已)。 警告:会影响性能。 |
n |
等价于 newline |
newline |
换行符 |
ndc |
NDC (nested diagnostic context) |
p |
等价于 level |
P |
等价于 property |
properties |
等价于 property |
property |
输出事件的特殊属性。例如: %property{user} 输出user属性。属性是由loggers或appenders添加到时间中的。 有一个默认的属性"DE>log4net:HostName"总是会有。DE> %property将输出所有的属性 。 (扩展后可以使用) |
r |
等价于 timestamp |
t |
等价于 thread |
timestamp |
从程序启动到事件发生所经过的毫秒数。 |
thread |
引发日志事件的线程,如果没有线程名就使用线程号。 |
type |
引发日志请求的类的全名。. 可以使用精度控制符。例如: 类名是 "log4net.Layout.PatternLayout", 格式模型是%type{1} 将输出"PatternLayout"。(也是从右开始的。) 警告:会影响性能。 |
u |
等价于 identity |
username |
当前用户的WindowsIdentity。(类似:HostName/Username) 警告:会影响性能。 |
utcdate |
发生日志事件的UTC时间。DE>后面还可以跟一个日期格式,用大括号括起来。DE>例如:%utcdate{HH:mm:ss,fff}或者%utcdate{dd MMM yyyy HH:mm:ss,fff}。如果utcdate后面什么也不跟,将使用ISO8601 格式 。 日期格式和.Net中DateTime类的ToString方法中使用的格式是一样。 另外log4net还有3个自己的格式Formatter。 它们是 "ABSOLUTE", "DATE"和"ISO8601"分别代表 AbsoluteTimeDateFormatter, DateTimeDateFormatter和Iso8601DateFormatter。例如:%date{ISO8601}或%date{ABSOLUTE}。 它们的性能要好于ToString。 |
w |
等价于 username |
x |
等价于 ndc |
X |
等价于 mdc |
% |
%%输出一个百分号 |
关于调用本地信息(caller location information)的说明:
%type %file %line %method %location %class %C %F %L %l %M 都会调用本地信息。这样做会影响性能。本地信息使用System.Diagnostics.StackTrace得到。.Net 1.0 不支持System.Diagnostics.StackTrace 类。
本地信息在调试模式下可以正常获取,在非调试模式下可能获取不到,或只能获取一部分。(根据我的测试,其实是需要有一个程序数据库(.pdb)文件。)
%property属性要用代码来设置才能使用(也就是扩展一下),
默认属性log4net:HostName不用设置。
转义字符的修饰符:
Format modifier |
left justify |
minimum width |
maximum width |
comment |
%20logger |
false |
20 |
none |
如果logger名不足20个字符,就在左边补空格。 |
%-20logger |
true |
20 |
none |
如果logger名不足20个字符,就在右边补空格。 |
%.30logger |
NA |
none |
30 |
超过30个字符将截断。 |
%20.30logger |
false |
20 |
30 |
logger名要在20到30之间,少了在左边补空格,多了截断。 |
%-20.30logger |
true |
20 |
30 |
logger名要在20到30之间,少了在右边补空格,多了截断。 |
8.2Layout类代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net.Layout;
using log4net.Layout.Pattern;
using System.Reflection;
using System.Collections;
using FastReflectionLib;
namespace TGLog.ExpandLayout2
{
public class ReflectionLayout : PatternLayout
{
public ReflectionLayout()
{
this.AddConverter("property", typeof(ReflectionPatternConverter));
}
}
public class ReflectionPatternConverter : PatternLayoutConverter
{
protected override void Convert(
System.IO.TextWriter writer,
log4net.Core.LoggingEvent loggingEvent
)
{
if (Option != null)
{
// 写入指定键的值
WriteObject(
writer,
loggingEvent.Repository,
LookupProperty(Option,
loggingEvent)
);
}
else
{
// 写入所有关键值对
WriteDictionary(
writer,
loggingEvent.Repository,
loggingEvent.GetProperties()
);
}
}
///
/// 通过反射获取传入的日志对象的某个属性的值
///
///
///
private object LookupProperty(
string property,
log4net.Core.LoggingEvent loggingEvent)
{
object propertyValue = string.Empty;
PropertyInfo propertyInfo =
loggingEvent.MessageObject.GetType().GetProperty(property);
if (propertyInfo != null)
{
propertyValue =
propertyInfo.GetValue(loggingEvent.MessageObject, null);
}
return propertyValue;
}
}
}
8.3 MyLogImpl类代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net.Core;
namespace TGLog.ExpandILog
{
public class MyLogImpl : LogImpl, IMyLog
{
///
/// The fully qualified name of this declaring type not the type of any subclass.
///
private readonly static Type ThisDeclaringType = typeof(MyLogImpl);
public MyLogImpl(ILogger logger)
: base(logger)
{
}
#region Implementation of IMyLog
public void Debug(int operatorID, string operand, int actionType,object message,
string ip, string browser, string machineName)
{
Debug(operatorID, operand, actionType, message,
ip, browser, machineName, null);
}
public void Debug(int operatorID, string operand, int actionType,object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsDebugEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
public void Info(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName)
{
Info(operatorID, operand, actionType, message, ip, browser, machineName, null);
}
public void Info(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsInfoEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
public void Warn(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName)
{
Warn(operatorID, operand, actionType, message, ip, browser, machineName, null);
}
public void Warn(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsWarnEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
public void Error(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName)
{
Error(operatorID, operand, actionType, message, ip, browser, machineName, null);
}
public void Error(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsErrorEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
public void Fatal(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName)
{
Fatal(operatorID, operand, actionType, message, ip, browser, machineName, null);
}
public void Fatal(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsFatalEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
#endregion Implementation of IMyLog
}
}
8.4 MyLogManager类代码
#region Copyright & License
//
// Copyright 2001-2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#endregion
using System;
using System.Reflection;
using System.Collections;
using log4net;
using log4net.Core;
using log4net.Repository;
using log4net.Repository.Hierarchy;
namespace TGLog.ExpandILog
{
public class MyLogManager
{
#region Static Member Variables
///
/// The wrapper map to use to hold the objects
///
private static readonly WrapperMap s_wrapperMap = new WrapperMap(newWrapperCreationHandler(WrapperCreationHandler));
#endregion
#region Constructor
///
/// Private constructor to prevent object creation
///
private MyLogManager() { }
#endregion
#region Type Specific Manager Methods
///
/// Returns the named logger if it exists
///
///
/// If the named logger exists (in the default hierarchy) then it
/// returns a reference to the logger, otherwise it returns
/// null.
///
/// The fully qualified logger name to look for
/// The logger found, or null
public static IMyLog Exists(string name)
{
return Exists(Assembly.GetCallingAssembly(), name);
}
///
/// Returns the named logger if it exists
///
///
/// If the named logger exists (in the specified domain) then it
/// returns a reference to the logger, otherwise it returns
/// null.
///
/// the domain to lookup in
/// The fully qualified logger name to look for
/// The logger found, or null
public static IMyLog Exists(string domain, string name)
{
return WrapLogger(LoggerManager.Exists(domain, name));
}
///
/// Returns the named logger if it exists
///
///
/// If the named logger exists (in the specified assembly's domain) then it
/// returns a reference to the logger, otherwise it returns
/// null.
///
/// the assembly to use to lookup the domain
/// The fully qualified logger name to look for
/// The logger found, or null
public static IMyLog Exists(Assembly assembly, string name)
{
return WrapLogger(LoggerManager.Exists(assembly, name));
}
///
/// Returns all the currently defined loggers in the default domain.
///
///
/// The root logger is not included in the returned array.
///
/// All the defined loggers
public static IMyLog[] GetCurrentLoggers()
{
return GetCurrentLoggers(Assembly.GetCallingAssembly());
}
///
/// Returns all the currently defined loggers in the specified domain.
///
/// the domain to lookup in
///
/// The root logger is not included in the returned array.
///
/// All the defined loggers
public static IMyLog[] GetCurrentLoggers(string domain)
{
return WrapLoggers(LoggerManager.GetCurrentLoggers(domain));
}
///
/// Returns all the currently defined loggers in the specified assembly's domain.
///
/// the assembly to use to lookup the domain
///
/// The root logger is not included in the returned array.
///
/// All the defined loggers
public static IMyLog[] GetCurrentLoggers(Assembly assembly)
{
return WrapLoggers(LoggerManager.GetCurrentLoggers(assembly));
}
///
/// Retrieve or create a named logger.
///
///
/// Retrieve a logger named as the
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.
///
/// By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.
///
/// The name of the logger to retrieve.
/// the logger with the name specified
public static IMyLog GetLogger(string name)
{
return GetLogger(Assembly.GetCallingAssembly(), name);
}
///
/// Retrieve or create a named logger.
///
///
/// Retrieve a logger named as the
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.
///
/// By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.
///
/// the domain to lookup in
/// The name of the logger to retrieve.
/// the logger with the name specified
public static IMyLog GetLogger(string domain, string name)
{
return WrapLogger(LoggerManager.GetLogger(domain, name));
}
///
/// Retrieve or create a named logger.
///
///
/// Retrieve a logger named as the
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.
///
/// By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.
///
/// the assembly to use to lookup the domain
/// The name of the logger to retrieve.
/// the logger with the name specified
public static IMyLog GetLogger(Assembly assembly, string name)
{
return WrapLogger(LoggerManager.GetLogger(assembly, name));
}
///
/// Shorthand for .
///
///
/// Get the logger for the fully qualified name of the type specified.
///
/// The full name of will
/// be used as the name of the logger to retrieve.
/// the logger with the name specified
public static IMyLog GetLogger(Type type)
{
return GetLogger(Assembly.GetCallingAssembly(), type.FullName);
}
///
/// Shorthand for .
///
///
/// Get the logger for the fully qualified name of the type specified.
///
/// the domain to lookup in
/// The full name of will
/// be used as the name of the logger to retrieve.
/// the logger with the name specified
public static IMyLog GetLogger(string domain, Type type)
{
return WrapLogger(LoggerManager.GetLogger(domain, type));
}
///
/// Shorthand for .
///
///
/// Get the logger for the fully qualified name of the type specified.
///
/// the assembly to use to lookup the domain
/// The full name of will
/// be used as the name of the logger to retrieve.
/// the logger with the name specified
public static IMyLog GetLogger(Assembly assembly, Type type)
{
return WrapLogger(LoggerManager.GetLogger(assembly, type));
}
#endregion
#region Extension Handlers
///
/// Lookup the wrapper object for the logger specified
///
/// the logger to get the wrapper for
/// the wrapper for the logger specified
private static IMyLog WrapLogger(ILogger logger)
{
return (IMyLog)s_wrapperMap.GetWrapper(logger);
}
///
/// Lookup the wrapper objects for the loggers specified
///
/// the loggers to get the wrappers for
/// Lookup the wrapper objects for the loggers specified
private static IMyLog[] WrapLoggers(ILogger[] loggers)
{
IMyLog[] results = new IMyLog[loggers.Length];
for (int i = 0; i < loggers.Length; i++)
{
results[i] = WrapLogger(loggers[i]);
}
return results;
}
///
/// Method to create the objects used by
/// this manager.
///
/// The logger to wrap
/// The wrapper for the logger specified
private static ILoggerWrapper WrapperCreationHandler(ILogger logger)
{
return new MyLogImpl(logger);
}
#endregion
}
}
8.5 IMyLog类代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
namespace TGLog.ExpandILog
{
public interface IMyLog : ILog
{
void Debug(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Debug(int operatorID, string operand, int actionType,object message,
string ip, string browser, string machineName, Exception t);
void Info(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Info(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, Exception t);
void Warn(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Warn(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, Exception t);
void Error(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Error(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, Exception t);
void Fatal(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Fatal(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, Exception t);
}
}
8.6附件
使用log4net记录日志
8.7参考
1、http://peibing211.blog.163.com/blog/static/37116360200992811595469/
2、http://www.cnblogs.com/qiangzi/archive/2009/09/10/1541023.html
3、http://blog.chinaunix.net/u/23701/showart_1414206.html
4、http://itrust.cnblogs.com/archive/2005/01/25/97225.html
5、http://www.cnitblog.com/seeyeah/archive/2009/09/20/61491.aspx
6、http://www.cnblogs.com/zhmore/archive/2009/03/19/1416707.html
7、http://blog.shinylife.net/blog/article.asp?id=948
8、http://www.cnblogs.com/manhoo/archive/2009/06/25/1511066.html