这边篇文章的目的是训练我们在项目中使用log4net,为了更加全面的使用log4net的功能,我们假设在app里面定义:
一个repository: 作为log4net的顶级容器。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<!-- 定义log4net的section,作为log4net的顶级容器,对于log4net里面的repository -->
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<!-- 默认的Repository -->
<log4net>
...
</log4net>
</configuration>
两个logger:一个默认的logger,即root,给全局使用。一个特殊命名的logger,可以只给特殊的类型使用。
<!-- 默认的Repository -->
<log4net>
<!-- 默认的Root Logger -->
<root>
<!-- level:All,Debug,Info,Warn,Error,Fatal,Off -->
<!-- 如果不需要记录日志设置为Off -->
<!-- 如果要记录Error和Fatal设置为Error -->
<!-- 如果要记录Warn,Error和Fatal设置为Warn,以此类推 -->
<level value="All" />
<!-- 引用Appender -->
<appender-ref ref="RollingFileAppender" />
</root>
<!-- 定义新Logger,自动继承Root Logger,并多两个Appender -->
<logger name="Log4NetLib.MyLib">
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="EventLogAppender" />
</logger>
...
</log4net>
多个logger之间的继承关系?
logger使用继承体系,继承规则类似于.NET中的名字空间。如果有两个logger,分别命名为a.b和a.b.c,那么我们说a.b是a.b.c的祖先,a.b.c是a.b的孩子。每一个logger都继承了祖先的属性。root是默认的logger,所有其他的logger都会继承它的属性。
在<root>标签里,可以定义level级别值。如果没有定义level的值,默认值为DEBUG。可以通过<appender-ref>标签定义日志对象使用的Appender对象。<appender-ref>引用了在其他地方定义的Appender对象。在一个logger对象中的设置会覆盖根日志的设置。而对Appender属性来说,子日志对象则会继承父日志对象的Appender列表。可以显式设置logger的additivity属性为false,这样就不会继承祖先的属性了。logger的additivity属性的默认值为true。
一个自定义的ObjectRenderer类型,可以控制专有类型输出。
ObjectRenderer默认输出是如何实现的?
1. string类型的数据。原样输出。
2. IEnumerable类型的数据,输出{a, b, c}。
3. Array类型的数据,输出int[] {1, 2, 3}。
4. DictionaryEntry类型的数据,输出key=value。
5. 其他输出为Object.ToString()的返回值。
如果还不能满足需求,自定义一个CustomExcpetionRenderer类型,并配置:
<log4net>
...
<renderer renderingClass="Log4NetLib.CustomExcpetionRenderer" renderedClass="Log4NetLib.MyException" />
</log4net>
CustomExcpetionRenderer类型实现IObjectRenderer接口,代码为:
public class CustomExcpetionRenderer : IObjectRenderer
{
public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
{
MyException myException = obj as MyException;
writer.WriteLine(string.Format("Transaction ID : {0}", myException.TransID));
writer.WriteLine(string.Format("Username : {0}", myException.Username));
Exception exception = obj as Exception;
while (exception != null)
{
WriteException(exception, writer);
exception = exception.InnerException;
}
}
private void WriteException(Exception ex, TextWriter writer)
{
writer.WriteLine(string.Format("Type: {0}", ex.GetType().FullName));
writer.WriteLine(string.Format("Message: {0}", ex.Message));
writer.WriteLine(string.Format("Source: {0}", ex.Source));
writer.WriteLine(string.Format("TargetSite: {0}", ex.TargetSite));
WriteExceptionData(ex, writer);
writer.WriteLine(string.Format("StackTrace: {0}", ex.StackTrace));
}
private void WriteExceptionData(Exception ex, TextWriter writer)
{
foreach (DictionaryEntry entry in ex.Data)
{
writer.WriteLine(string.Format("{0}: {1}", entry.Key, entry.Value));
}
}
}
MyException的代码如下:
public class MyException : ApplicationException
{
public string TransID;
public string Username;
public MyException(string message) : base(message)
{
}
}
这样在代码中打印MyException对象的时候,会输出自定义的格式。
三个Appenders: RollingFileAppender、EventLogAppender和ConsoleAppender。
RollingFileAppender配置为:
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<!-- 文件路径 -->
<file value="logs\\" />
<datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.log'" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<staticLogFileName value="false"/>
<maxSizeRollBackups value="100" />
<maximumFileSize value="10MB" />
<!-- 定义layout -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{host} %appdomain %date %level %logger %user %message %stacktracedetail%newline" />
</layout>
<!-- 定义filter -->
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info"/>
<param name="LevelMax" value="Error"/>
</filter>
</appender>
ConsoleAppender配置为:
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<ConversionPattern value="%property{host} %appdomain %date %level %logger %user %message %stacktracedetail%newline" />
</layout>
<!-- 定义filter -->
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info"/>
<param name="LevelMax" value="Error"/>
</filter>
</appender>
EventLogAppender配置为:
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<ApplicationName value="MY-AWESOME-APP" />
<layout type="log4net.Layout.PatternLayout">
<ConversionPattern value="%property{host} %appdomain %date %level %logger %user %message %stacktracedetail%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Error"/>
<param name="LevelMax" value="Error"/>
</filter>
</appender>
注意配置EventLogAppender的时候,需要定义ApplicationName为MY-AWESOME-APP,并添加配置表Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\MY-AWESOME-APP,设置里面Key-value为EventMessageFile: C:\Windows\Microsoft.NET\Framework\v4.0.30319\EventLogMessages.dll 不然会无法记录日志。
我们在appender中选择LevelRangeFilter类型来定义Filter。
Appender不设置Filter,默认filter是什么?
默认会记录所有的日志。
其实Appender可以设置多个filter。
1. 设置LevelMatchFilter和StringMatchFilter两个Filter
<filter type="log4net.Filter.LevelMatchFilter">
<param name="LevelToMatch" value="Debug" />
</filter>
<filter type="log4net.Filter.StringMatchFilter">
<param name="StringToMatch" value="Debug" />
</filter>
这样设置两个Filter,到底记不记日志,取决于两个Filter的并集,有一个条件匹配就会记录。
2. 为多个Filter设置AcceptOnMatch属性
<filter type="log4net.Filter.LevelMatchFilter">
<param name="LevelToMatch" value="Debug" />
<AcceptOnMatch value="false"></AcceptOnMatch>
</filter>
<filter type="log4net.Filter.StringMatchFilter">
<param name="StringToMatch" value="Debug" />
</filter>
如果这样写的话,即使第一个Filter符合了条件,也会询问第二个Filter是否符合条件。
选择PatternLayout排版进行输出。PatternLayout因为实在太好使用,基本上能完成我们的所有需求。
完成这些配置文件之后,我们需要在项目中写代码对log4net进行调用,首先加载配置文件:
log4net.Config.XmlConfigurator.Configure();
把机器名称保存在GlobalContext.Properties中:
log4net.GlobalContext.Properties["host"] = Environment.MachineName;
获取一个ILog:
var _log = LogFactory.GetLogger(typeof(Program));//root
var _log = LogFactory.GetLogger("Log4NetLib.MyLib");//logger name="Log4NetLib.MyLib"
public static class LogFactory
{
public static ILog GetLogger(Type type)
{
return LogManager.GetLogger(type);
}
public static ILog GetLogger(string str)
{
return LogManager.GetLogger(str);
}
}
写日志:
_log.Info("MyException Info");
//会输出自定义的格式。
_log.Info(ex);
//会输出自定义的格式。
_log.Error("MyLib MyException", ex);
通过这篇文章我们很好的学习了log4net到底如何使用,以及它强大的配置能力。