log4net.是.NET下面最伟大的日志工具之一。简单、强大、可扩展,简直是日志工具的黄金标准. 在我看来惟一欠缺是一个比较直接的使用指南。 这个文档,在深度主要讲如何使用,但它仍是有点模糊。基本上,若是你已经知道log4net能作什么,若是你只是想知道语法,那么这个文档就适合你了.外面的文档一般是针对一类系统. 我但愿个人这份指南能有所突破,我会提供一份完整的指南,包含了一些为曾经遇到的问题。下面的例子和信息是基于log4net组提供的文档的基础上编写的. web
log4net有三个部分组成:配置、安装、和调用. 配置一般在app.config 或 web.config 文件中. 为,咱们下面会深刻的讲解这一块. 若是你想经过独立的配置文件来提高可扩展性,请看 "Getting Away from app.config"这一节. 不管你选择哪种配置方式,setup相关的代码是必须的,经过这些代码创建与日志模块的通道.最后,最简单部分就是调用相关写日志的方法。数据库
一共有7个日志等级,其中有5种等级你能够经过代码调用。他们是下面几种 (等级从高到低):app
一般创建一个log4net 日志器的标准方法,在桌面程序中在app.config文件中配置,web程序则在web.config文件中配置. 为了能让log4net正常工做,须要在配置文件增长几项配置,下面章节将详细说明相关配置,修改配置文件后,无需从新编译.框架
<root> <level value="INFO"/> <appender-ref ref ="FileAppender" /> <appender-ref ref="ConsoleAppender" /> </root> <!--Additivity的值缺省是true--> <logger name="testApp.Logging" additivity="false"> </logger>
<logger name="Log4NetTest.OtherClass"> <level value="DEBUG"/> <appender-ref ref="ConsoleAppender"/> </logger>
注意这里的 logger名称是带命名空间的完整的类名称。若是你想监测整个命名空间,这里只要改为命名空间名称便可. 我不建议在多个logger中复用appenders ,这可能会带来不可预知的后果。ide
由于在一个配置文件中,除了log4net相关的配置信息外,每每还有其余的配置信息。因此你须要指定一个配置段用来标识log4net配置所在位置。下面是一个例子用来表示log4net的相关配置信息位于"log4net
"这个XML标签下:函数
<configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections>
appender用来配置日志的相关信息.用来指定日志信息写在哪里,如何写,以及在什么状况下写日志. 不一样的appender 可能会有不一样的parameters ,但有一些是共性的元素,首先是名字(name)和类型( type)。 每一个appender 必须被命名,且必须指定一种类型,下面是一个appender实例:工具
<appender name="LogFileAppender" type="log4net.Appender.FileAppender" > <param name="File" value="log-file.txt" /> <param name="AppendToFile" value="true" /> <layout type="log4net.Layout.PatternLayout"> <param name="Header" value="[Header]\r\n"/> <param name="Footer" value="[Footer]\r\n"/> <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="DEBUG" /> <param name="LevelMax" value="WARN" /> </filter> </appender>
在每一个appender中必需要有一个layout配置. 使用不一样类型的Layout可能会有一点不一样,可是基本的东西都是同样的. 你须要指定一种类型来指明如何写日志。有多种选择,可是为我建议你使用PatternLayout. This will allow you to specify how you want your data written to the data repository. 若是你使用PatternLayout,你须要定义一个子项,来指定转换格式.下面我和会针对转换格式进行详细讲解, 这里是一个关于 pattern layout 的简单例子:性能
<layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline"/>
</layout>
就如为上面所提到的,转换格式是用于针对PatternLayout类型的appender ,指定如何存储信息. 转换格式中有不少关键字,就像字符串转义符同样。这里我将针对几个我认为比较有用和重要的进行介绍. 完整的转换格式列表能够看log4net 文档.测试
%date
- 将时间以本地时区格式输出. 例如能够用带“{}”的格式描述符%date{MMMM dd, yyyy HH:mm:ss, fff} 输出时间字符串: "January 01, 2011 14:15:43, 767". 可是通常建议使用log4net 自动的时间格式 (ABSOLUTE, DATE, or ISO8601) ,由于性能会更好.网站
%utcdate
-这个与 %date
基本相同,可是它输出的是通用时间(格林威治时),其余的都同样.
%exception
- If an exception is passed in, it will be entered and a new line will be placed after the exception. If no exception is passed in, this entry will be ignored and no new line will be put in. This is usually placed at the end of a log entry, and usually a new line is placed before the exception as well.
%level
- 用于指定时间的等级 (DEBUG, INFO, WARN, etc.).
%message
- 输出的日志消息,如ILog.Debug(…)输出的一条消息.
%newline
- 这是新增一行,基于应用程序运行的平台,他将转换为指定指定平台的换行符。使用这个转换符和使用特定平台的的换行符相比,没有性能差别。
%timestamp
- 从应用程序启动起的毫秒数.
%thread
- 发起写日志的线程名称(线程若是没有命名,则显示线程ID)
除了以上这些,还有一些比较有用可是要慎用的转换符。这些转换符的使用可能会给性能带来负面影响,以下:
%identity
- 当前使用 Principal.Identity.Name
方法的用户标识.
%location
- 在Debug 模式下特别有用,用来显示在哪里调用写日志的的方法(行数,方法名等). 可是在Release模式下,信息会变少.
%line
- 调用的代码行号.
%method
-调用的方法名.
%username
- 输出 WindowsIdentity
属性.
你可能会发现有些是采用字母而不是名称(如:%m 对应%message),这是一种简写,咱们在这里不作展开了. 另外须要注意每个转换格式均可以指定输出长度,为了长度规整,会自动增长空格或对内容进行截取.基本的语法是在%符号和名字中加填写一个数字:
X
- 指定最小字符数,不足指定最小字符数的将自动在字符串左边补足空字符串. For example, %10message
will give you " hi
".-X
-与上面同样,只不过是补在字符串右边, %-10message
will give you "hi
"..X
- 指定最大字符数 ,注意若是超过最大字符串,则从字符串的头部截取而不是尾部. 例如,若是输入"Error entry
" , %.10message返回
"rror entry
" 。你也能够将两种组合起来使用,像这样: "%10.20message
",若是输入不足10,则在左边补空格,若是超过20个字节,则从起始位置截取.
filter是appender中的一个重要部分,经过Filters,你能够指定日志等级,甚至能够查找消息中的关键字。Filters 能够混合使用,可是使用时须要当心. 当一个消息符合过滤器条件的时候,它将被写入日志,而且当前这个过滤器的处理就结束了。所以当你作一个复杂过滤的时候,过滤器的顺序就变得尤其重要.
<filter type="log4net.Filter.StringMatchFilter"> <stringToMatch value="test" /> </filter> <filter type="log4net.Filter.DenyAllFilter" />
一个级别范围过滤器用来告诉系统,只有在指定范围内的级别日志才会记录,所以,在下面的例子中 INFO, WARN, ERROR, 或 FATAL级别的日志将被记录。可是DEBUG 级别的日志将被忽略。这里不须要在最后添加DenyAllFilter 过滤器,由于它隐含表示 不在该范围内被拒绝记录。
<filter type="log4net.Filter.LevelRangeFilter"> <levelMin value="INFO" /> <levelMax value="FATAL" /> </filter>
级别匹配过滤器和级别范围过滤器同样,只不过它仅针对单个级别进行匹配。可是它并不隐含不匹配就拒绝记录日志的规则。因此咱们须要在最后加上DenyAllFilter 过滤器
<filter type="log4net.Filter.LevelMatchFilter"> <levelToMatch value="ERROR"/> </filter> <filter type="log4net.Filter.DenyAllFilter"/>
若是忘记了这个过滤器,你的appender 将不能按预想的逻辑工做. 这个过滤器的目的就是指定全部内容都不作日志记录.若是只有这一个过滤器,那么什么内容都不会记录日志.
<filter type="log4net.Filter.DenyAllFilter" />
每一类appender 由于其存储数据的位置不一样,都有其本身的语法集合。其中记录到数据库的方式是最不一样寻常的。我将列出一些我认为最经常使用的类型进行介绍。然而,经过上面讲的这些信息,你可能已经能使用网上给出的例子. log4net官方网站有不少针对不一样类型appenders的例子.就像我以前所说的,经过阅读log4net 的文档,通常都不会有什么问题.我通常都拷贝他们的例子,而后根据本身的须要进行修改.
我一般在测试中使用这类appender ,可是它在实际产品中也是颇有用的。它将日志写到输出窗口,若是是控制台程序,则写到命令窗口。下面的例子会输出这样的日志: "2010-12-26 15:41:03,581 [10] WARN Log4NetTest.frmMain - This is a WARN test." 并在最后有一个换行.
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date{ABSOLUTE} [%thread] %level %logger - %message%newline"/> </layout> <filter type="log4net.Filter.StringMatchFilter"> <stringToMatch value="test" /> </filter> <filter type="log4net.Filter.DenyAllFilter" />
</appender>
这类appender 将把日志写到text文件中。这里咱们须要注意的是,咱们必须指定text文件的名字(在下面这个例子中,日志文件的名字是mylogfile.txt 这个文件将保存在应用程序同一目录下) ,咱们已经指定了追加的模式(而非覆盖模式),咱们还指定了Minimal Lock ,以确保这个文件不会被多个 appenders影响。
<appender name="FileAppender" type="log4net.Appender.FileAppender"> <file value="mylogfile.txt" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %level %logger - %message%newline" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <levelMin value="INFO" /> <levelMax value="FATAL" /> </filter> </appender>
这个appender 能够用在全部使用File appender 的地方。其功能和File appender 基本同样,只不过额外增长了设置文件大小的功能,超过文件大小则新写一个文件。 这样你就不须要小心长时间运行的日志文件过载问题。若是没有采用这种appender ,只要写一个文件的时间足够长,甚至一个小应用程序均可能压垮操做系统的文件系统。下面的例子中,我将记录与上面file appender相似式样的日志。可是我指定了日志文件的大小为10MB,而且在我删除以前,指定保留存储5个归档文件。这归档文件的名字和日志文件名相同,只不事后面跟了“.”和数字(例如: mylogfile.txt.2 表示第二个归档文件).staticLogFileName
属性确保当前日志文件以 file 标签里定义的命名。(在个人例子中是: mylogfile.txt).
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="mylogfile.txt" /> <appendToFile value="true" /> <rollingStyle value="Size" /> <maxSizeRollBackups value="5" /> <maximumFileSize value="10MB" /> <staticLogFileName value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %level %logger - %message%newline" /> </layout> </appender>
public sealed class Logger { #region [ 单例模式 ] private static readonly Logger _logger = new Logger(); private static readonly log4net.ILog _Logger4net = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// <summary> /// 无参私有构造函数 /// </summary> private Logger() { } /// <summary> /// 获得单例 /// </summary> public static Logger Singleton { get { return _logger; } } #endregion #region [ 参数 ] public bool IsDebugEnabled { get { return _Logger4net.IsDebugEnabled; } } public bool IsInfoEnabled { get { return _Logger4net.IsInfoEnabled; } } public bool IsWarnEnabled { get { return _Logger4net.IsWarnEnabled; } } public bool IsErrorEnabled { get { return _Logger4net.IsErrorEnabled; } } public bool IsFatalEnabled { get { return _Logger4net.IsFatalEnabled; } } #endregion #region [ 接口方法 ] #region [ Debug ] public void Debug(string message) { if (this.IsDebugEnabled) { this.Log(LogLevel.Debug, message); } } public void Debug(string message, Exception exception) { if (this.IsDebugEnabled) { this.Log(LogLevel.Debug, message, exception); } } public void DebugFormat(string format, params object[] args) { if (this.IsDebugEnabled) { this.Log(LogLevel.Debug, format, args); } } public void DebugFormat(string format, Exception exception, params object[] args) { if (this.IsDebugEnabled) { this.Log(LogLevel.Debug, string.Format(format, args), exception); } } #endregion #region [ Info ] public void Info(string message) { if (this.IsInfoEnabled) { this.Log(LogLevel.Info, message); } } public void Info(string message, Exception exception) { if (this.IsInfoEnabled) { this.Log(LogLevel.Info, message, exception); } } public void InfoFormat(string format, params object[] args) { if (this.IsInfoEnabled) { this.Log(LogLevel.Info, format, args); } } public void InfoFormat(string format, Exception exception, params object[] args) { if (this.IsInfoEnabled) { this.Log(LogLevel.Info, string.Format(format, args), exception); } } #endregion #region [ Warn ] public void Warn(string message) { if (this.IsWarnEnabled) { this.Log(LogLevel.Warn, message); } } public void Warn(string message, Exception exception) { if (this.IsWarnEnabled) { this.Log(LogLevel.Warn, message, exception); } } public void WarnFormat(string format, params object[] args) { if (this.IsWarnEnabled) { this.Log(LogLevel.Warn, format, args); } } public void WarnFormat(string format, Exception exception, params object[] args) { if (this.IsWarnEnabled) { this.Log(LogLevel.Warn, string.Format(format, args), exception); } } #endregion #region [ Error ] public void Error(string message) { if (this.IsErrorEnabled) { this.Log(LogLevel.Error, message); } } public void Error(string message, Exception exception) { if (this.IsErrorEnabled) { this.Log(LogLevel.Error, message, exception); } } public void ErrorFormat(string format, params object[] args) { if (this.IsErrorEnabled) { this.Log(LogLevel.Error, format, args); } } public void ErrorFormat(string format, Exception exception, params object[] args) { if (this.IsErrorEnabled) { this.Log(LogLevel.Error, string.Format(format, args), exception); } } #endregion #region [ Fatal ] public void Fatal(string message) { if (this.IsFatalEnabled) { this.Log(LogLevel.Fatal, message); } } public void Fatal(string message, Exception exception) { if (this.IsFatalEnabled) { this.Log(LogLevel.Fatal, message, exception); } } public void FatalFormat(string format, params object[] args) { if (this.IsFatalEnabled) { this.Log(LogLevel.Fatal, format, args); } } public void FatalFormat(string format, Exception exception, params object[] args) { if (this.IsFatalEnabled) { this.Log(LogLevel.Fatal, string.Format(format, args), exception); } } #endregion #endregion #region [ 内部方法 ] /// <summary> /// 输出普通日志 /// </summary> /// <param name="level"></param> /// <param name="format"></param> /// <param name="args"></param> private void Log(LogLevel level, string format, params object[] args) { switch (level) { case LogLevel.Debug: _Logger4net.DebugFormat(format, args); break; case LogLevel.Info: _Logger4net.InfoFormat(format, args); break; case LogLevel.Warn: _Logger4net.WarnFormat(format, args); break; case LogLevel.Error: _Logger4net.ErrorFormat(format, args); break; case LogLevel.Fatal: _Logger4net.FatalFormat(format, args); break; } } /// <summary> /// 格式化输出异常信息 /// </summary> /// <param name="level"></param> /// <param name="message"></param> /// <param name="exception"></param> private void Log(LogLevel level, string message, Exception exception) { switch (level) { case LogLevel.Debug: _Logger4net.Debug(message, exception); break; case LogLevel.Info: _Logger4net.Info(message, exception); break; case LogLevel.Warn: _Logger4net.Warn(message, exception); break; case LogLevel.Error: _Logger4net.Error(message, exception); break; case LogLevel.Fatal: _Logger4net.Fatal(message, exception); break; } } #endregion }//end of class #region [ enum: LogLevel ] /// <summary> /// 日志级别 /// </summary> public enum LogLevel { Debug, Info, Warn, Error, Fatal } #endregion
别忘了,须要在类定义前加上一句:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
不然什么都不会写哦。
你可能想在独立的配置文件中进行log4net 的配置.事实上, 你可能会发现这是一种最佳的配置方式,由于你能够在你的不一样的项目中造成不一样的标准配置文件。这有助于减小开发时间,及是配置文件标准化。要实现这一目的,你只要在你的程序的两个地方进行修改便可。首先,你须要将你的配置文件保存成另外一个文件。 除了不在app.config 或web.config 文件中外,其余的格式都同样。第二点须要改变的是在setup调用的地方,以下:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "MyStandardLog4Net.config", Watch = true)]
在上面这行代码中,你也能够用"ConfigFileExtension
"后缀代替 "ConfigFile
"。这样,你须要把你的配置文件名称改为你的assembly 名称。以下所示:
[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "mylogger", Watch = true)]
在上面这个例子中,若是咱们的应用程序名字叫 test.exe,那么log4net 配置文件的名字为 :text.exe.mylogger.
下面是一个空白的配置文件模版
<!--This is the root of your config file--> <configuration> <!-- Level 0 --> <!--This specifies what the section name is--> <configSections> <!-- Level 1 --> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> <!-- Level 2 --> </configSections> <log4net> <!-- Level 1 --> <appender> <!-- Level 2 --> <layout> <!-- Level 3 --> <conversionPattern /> <!-- Level 4 --> </layout> <filter> <!-- Level 3 --> </filter> </appender> <root> <!-- Level 2 --> <level /> <!-- Level 3 --> <appender-ref /> <!-- Level 3 --> </root> <logger> <!-- Level 2 --> <level /> <!-- Level 3 --> <appender-ref /> <!-- Level 3 --> </logger> </log4net> </configuration>