Web项目中使用Log4net 案例
简介:
几乎所有的大型应用都会有自己的用于跟踪调试的API。因为一旦程序被部署以后,就不太可能再利用专门的调试工具了。然而一个管理员可能需要有一套强大的日志系统来诊断和修复配置上的问题。
经验表明,日志记录往往是软件开发周期中的重要组成部分。它具有以下几个优点:它可以提供应用程序运行时的精确环境,可供开发人员尽快找到应用程序中的Bug;一旦在程序中加入了Log 输出代码,程序运行过程中就能生成并输出日志信息而无需人工干预。另外,日志信息可以输出到不同的地方(控制台,文件等)以备以后研究之用。
Log4net就是为这样一个目的设计的,用于.NET开发环境的日志记录包。
官方网站:http://logging.apache.org/log4net/
使用方法:
1、下载Log4Net,地址如下:http://logging.apache.org/log4net/download_log4net.cgi , 解压
2、 在Web 项目中添加 log4net.dll 文件的引用。
3、在Web项目根目录下创建log4net.config配置文件(也可以直接添加到webconfig文件中)
log4net.config 文件配置如下:
配置文件代码:
<?xml version="1.0" encoding="utf-8"?> <configuration> <!-- Register a section handler for the log4net section --> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler"/> </configSections> <log4net> <!--声明跟节点 和设置 默认level--> <!--在框架的体系里,所有的日志对象都是根日志(root logger)的后代。 因此如果一个日志对象没有在配置文件里显式定义,则框架使用根日志中定义的属性。在<root>标签里,可以定义level级别值和Appender的列表。如果没有定义LEVEL的值,则缺省为DEBUG。可以通过<appender-ref>标签定义日志对象使用的Appender对象。<appender-ref>声明了在其他地方定义的Appender对象的一个引用。在一个logger对象中的设置会覆盖根日志的设置。而对Appender属性来说,子日志对象则会继承父日志对象的Appender列表。这种缺省的行为方式也可以通过显式地设定<logger>标签的additivity属性为false而改变。 <logger name="testApp.Logging" additivity="false"></logger> Additivity的值缺省是true.--> <root> <!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) --> <level value="ALL"/> <appender-ref ref="RollingLogFileAppender" /> </root> <!--定义logger实例--> <!--<logger> 元素预定义了一个具体日志对象的设置。然后通过调用LogManager.GetLogger(“RollingFileAppender”)函数,你可以检索具有该名字的日志。如果LogManager.GetLogger(…)打开的不是预定义的日志对象,则该日志对象会继承根日志对象的属性。知道了这一点,我们可以说,其实<logger>标签并不是必须的。--> <logger name="RollingFileAppender"> <level value="DEBUG"/> <appender-ref ref="RollingLogFileAppender" /> </logger> <logger name="FileAppender"> <level value="DEBUG"/> <appender-ref ref="FileAppender" /> </logger> <!--设置appender 形式--> <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <!--日志路径--> <file type="log4net.Util.PatternString" value="Log/%date{yyyy-MM}/"/> <!--是否是向文件中追加日志--> <appendToFile value="true"/> <!--指明日志滚动方式。"Composite"指文件名同时按size和date来命名,一般就用这个。还有其他3个取值:Once(每次程序启动新生成一个)、Size、Date。当RollingStyle=Composite时,如果File参数设为"D:\WebTest\MyLog_" ,那么文件名将是:"MyLog_2015-11-27.txt--> <rollingStyle value="Date"/> <!--日志文件名格式为:2018-02-05.LOG--> <datePattern value="yyyy-MM-dd.LOG"/> <!--日志文件名是否是固定不变的--> <staticLogFileName value="false"/> <!--限定每个日志文件不超过10M--> <maximumFileSize value="10000" /> <!--到达限制大小后会生成一个新文件,如"2015-11-27.txt.1",依此类推,当生成"2015-11-27.txt.10"之后,再满了就要回头覆盖第一个文件了--> <maxSizeRollBackups value="10" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline %nLog Time:%utcdate %nThread ID:[%thread] %nLog %method Level: %-5level %n%message%newline %n"/> </layout> </appender> <appender name="FileAppender" type="log4net.Appender.FileAppender"> <file value="log-file.txt" /> <appendToFile value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> </layout> </appender> <!--log4net.Layout.PatternLayout中的转换模式(ConversionPattern)--> <!-- %m(message):输出的日志消息,如ILog.Debug(…)输出的一条消息 %n(new line):换行 %d(datetime):输出当前语句运行的时刻 %r(run time):输出程序从运行到执行到当前语句时消耗的毫秒数 %t(thread id):当前语句所在的线程ID %p(priority): 日志的当前优先级别,即DEBUG、INFO、WARN…等 %c(class):当前日志对象的名称,例如: 模式字符串为:%-10c -%m%n 代码为: ILog log=LogManager.GetLogger(“Exam.Log”); log.Debug(“Hello”); 则输出为下面的形式: Exam.Log - Hello %L:输出语句所在的行号 %F:输出语句所在的文件名 %-数字:表示该项的最小长度,如果不够,则用空格填充 例如,转换模式为%r [%t]%-5p %c - %m%n 的 PatternLayout 将生成类似于以下内容的输出: 176 [main] INFO org.foo.Bar - Located nearest gas station. --> </log4net> </configuration>
4、在项目中添加一个LogHelper.cs的类 方便在项目其他页面中调用
LogHelper.cs 代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using log4net; using System.IO; using System.Diagnostics; namespace Log4net_Demo.Common { public class LogHelper { public static ILog log; static LogHelper() { } public static void Info(object message) { if (log.IsInfoEnabled) { log.Info(message); } } public static void Info(object message, Exception exception) { if (log.IsInfoEnabled) { //add common logs log.Info(message, exception); } } public static void Error(object message) { if (log.IsErrorEnabled) { //add error logs log.Error(message); } } public static void Error(object message, Exception exception) { if (log.IsErrorEnabled) { //add error logs log.Error(message, exception); } } public static void Warn(object message) { if (log.IsWarnEnabled) { //add warning logs log.Warn(message); } } public static void Warn(object message, Exception exception) { if (log.IsWarnEnabled) { //add warning logs log.Warn(message, exception); } } public static void Debug(object message) { if (log.IsDebugEnabled) { //add debug logs log.Debug(message); } } #region logapp public static void Info(string logAppender, object message, string fileName = null) { GetLogger(logAppender, fileName); if (log.IsInfoEnabled) { log.Info(message); } } static string baseLogDirectory = $"{AppDomain.CurrentDomain.BaseDirectory}\\Log\\{DateTime.Now.ToString("yyyy-MM")}\\FIMService\\"; private static void GetLogger(string logAppender, string fileName) { try { if (!string.IsNullOrEmpty(fileName))//若FileName不为空,则修改写入文件名称 { var repository = LogManager.GetRepository(); var appenders = repository.GetAppenders(); var targetApder = appenders.First(p => p.Name == $"{logAppender}FileAppender") as log4net.Appender.RollingFileAppender; if (string.IsNullOrEmpty(baseLogDirectory)) { baseLogDirectory = targetApder.File; } targetApder.File = $"{baseLogDirectory}{fileName}"; //targetApder.Writer = new System.IO.StreamWriter(targetApder.File, targetApder.AppendToFile, targetApder.Encoding);//只更新Write方法,Log日志无法写入,暂未找到解决方案 //激活更改,缺点:会更新Repository targetApder.ActivateOptions(); } log = LogManager.GetLogger(logAppender);//重新获取Logger } catch (Exception ex) { if (!EventLog.SourceExists("My Application")) EventLog.CreateEventSource("My Application", "System"); EventLog eventLog = new EventLog("System"); eventLog.Source = "My Application"; eventLog.WriteEntry(string.Format("log4net error , message {0}", ex.Message)); } } public static void Info(string logAppender, object message, Exception exception) { log = LogManager.GetLogger(logAppender); if (log.IsInfoEnabled) { //add common logs log.Info(message, exception); } } public static void Error(string logAppender, object message) { log = LogManager.GetLogger(logAppender); if (log.IsErrorEnabled) { //add error logs log.Error(message); } } public static void Error(string logAppender, object message, Exception exception) { log = LogManager.GetLogger(logAppender); if (log.IsErrorEnabled) { //add error logs log.Error(message, exception); } } public static void Warn(string logAppender, object message) { log = LogManager.GetLogger(logAppender); if (log.IsWarnEnabled) { //add warning logs log.Warn(message); } } public static void Warn(string logAppender, object message, Exception exception) { log = LogManager.GetLogger(logAppender); if (log.IsWarnEnabled) { //add warning logs log.Warn(message, exception); } } public static void Debug(string logAppender, object message) { log = LogManager.GetLogger(logAppender); if (log.IsDebugEnabled) { //add debug logs log.Debug(message); } } public static void Debug(string logAppender, object message, Exception exception) { log = LogManager.GetLogger(logAppender); if (log.IsDebugEnabled) { //add debug logs log.Debug(message, exception); } } #endregion /// <summary> /// 输出日志到Log4Net /// </summary> /// <param name="t"></param> /// <param name="ex"></param> #region static void WriteLog(Type t, Exception ex) public static void WriteLog(Type t, Exception ex) { log4net.ILog log = log4net.LogManager.GetLogger(t); log.Error("Error", ex); } #endregion /// <summary> /// 输出日志到Log4Net /// </summary> /// <param name="t"></param> /// <param name="msg"></param> #region static void WriteLog(Type t, string msg) public static void WriteLog(Type t, string msg) { log = log4net.LogManager.GetLogger(t); log.Error(msg); } #endregion } }
5、在项目代码中读取log4net.config 配置,这里有4中读取配置的方法。
a、在该web项目中的AssemblyInfo.cs文件中添加(注意放对位置,放在命名空间外)
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
b、Global.asax.cs中添加(位置也是在命名空间外) [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
c、 在Global.asax.cs中 Application_Start方法中添加 log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo($@"{ AppDomain.CurrentDomain.BaseDirectory }\log4net.config"));
d、直接在要调用的controller\页面上添加 (位置也是在命名空间外) [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)] 我个人不推荐这种方法 太繁重了 因为一个项目不可能就一两个页面 要 用到log日志功能的
6、在代码中使用log4net 记录错误日志 使用前面新建的LogHelper.cs 直接记录,页面传id=0 进入HomeController
代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Log4net_Demo.Common; namespace Log4net_Demo.Controllers { public class HomeController : Controller { // GET: Home public ActionResult Index(int id) { try { int result = 8/id; } catch (Exception e) { LogHelper.Error(LogAppender.RollingFileAppender, e.ToString(), e); } return View(); } } }
结果: