【5】基于Log4Net的日志系统

阅读目录

  • 日志系统应具备的特性
  • Log4Net
  • 配置文件:log4net.config
  • 初始化
  • 输出信息
  • 对Log4Net的封装
  • log4net.config复杂配置

不管是Web应用程序还是WinForm应用程序,Visual Studio所带的调试功能都是足够强大,足以应付开发中的各种调试需求。但是,对于已经发布的应用,要记录错误、记载运行中的各种状态信息,就需要依靠日志系统了。

日志系统应具备的特性

一个好的日志系统,应该具备以下的特性:

1、运行稳定。因为日志的作用就是要在系统出现各种错误、各种异常的时候输出信息,因此,它必须具有足够的鲁棒性和稳定性,在任何时候都能发挥其功能。

2、适用性广。需要用到日志功能的地方,在程序中可以说无处不在:ASPX页面,WinForm窗体,类文件、ASHX页面、线程……因此,日志系统应当在任何位置都能发挥其功能。

3、分级管理。日志应当可以按照重要性分为不同的级别,如Info、Debug、Warning、Error、Fatal等。用户可以决定输出何种级别的日志。调试时,可以输出尽可能全面的信息,如Info、Debug等级别的信息都可以输出。部署后,仅仅输出Warning以上的级别。

4、输出丰富。可以根据用户的需求,按用户指定的格式输出日志。

Log4Net

上述的特征,其实就是Log4Net的特点。它来源于Java平台中著名的日志组件log4j,是一个非常成熟的日志系统。它的版本更新极慢,但即使是从在.Net 1.0下发布的版本,在后面的.Net版本中都能工作正常!

由于Log4Net是开源的,所以,可以对它进行各种各样的定制修改。官方网站地址是http://logging.apache.org/log4net/

介绍Log4Net的文章较多,因此在此不打算重复这些细节。本着最快实现的目标,争取把达到目标的必须的几个关键点点到即可。

配置文件:log4net.config

log4net的工作原理很简单,在代码中使用log4net的相应方法(从Info到Fatal)输出日志信息,而最终究竟输出到哪里?输出哪些都由log4net.config这个配置文件来控制。因此log4net.config的重要性可谓关键。下面是一个典型的配置文件,其实有它基本就够了!

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <log4net>
    <!--错误日志,保存到一个文件Error.log中-->
    <appender name="Log" type="log4net.Appender.FileAppender">
      <file value="log/log.txt" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="[%date{yyyy-MM-dd HH:mm:ss}]%message - (%logger)%newline" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="DEBUG" />
        <param name="LevelMax" value="FATAL" />
      </filter>
    </appender> 
    
    <root>
      <level value="ALL" />
      <appender-ref ref="Log" />
    </root>
  </log4net> 
</configuration>

初始化

Log4Net作为一个全局的基础设置,因此必须要进行一个初始化。在Web程序和窗体程序中有所不同。

1、在WinForm应用程序中,需要显示调用以下语句:

log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(System.Windows.Forms.Application.StartupPath + "\\log4net.config"));

2、Web应用程序,也可以通过调用初始化语句完成:

log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(System.Web.HttpContext.Current.Server.MapPath("~")+"\\log4net.config"));

但是,由于Web应用程序不像WinForm应用程序那样有明确的入口点,所以Web程序的初始化往往在global.ascx中的Application_Start中添加设置,如下所示:

void Application_Start(object sender, EventArgs e) 
{
	// 在应用程序启动时运行的代码
	log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(Server.MapPath("~")+"\\log4net.config"));
}

所以,对Web程序,只要添加global.ascx,在Application_Start中添加代码即可。

输出信息

Log4Net输出信息的主要方法就是Debug()、Error()等方法,关键点在于获取Logger对象。有多种方法可以获取Logger对象,经过实验,使用下面的方法可以适用于普通类和静态类的输出:

 log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType).Info("ColumnClick"); 

在WinForm中进行简单的测试:

private void button1_Click(object sender, EventArgs e)
{
	log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType).Debug("普通类中的信息");
	SClass.StaticFunc();
	for (int i = 0; i < 5; i++)
	{
		(new Thread(test)).Start();
	}
}
void test()
{
	log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType).Debug("线程中:"+Thread.CurrentThread.ManagedThreadId.ToString());
}

其中SClass中的StaticFunc是一个简单静态方法,其中有日志信息输出。最后的日志如下:

而在Web应用程序中,也可以进行类似的测试,证明适应性还是不错的。

对Log4Net的封装

经过各种测试,终于找到一些通用性强的方法,为防止以后每次都得回来复制粘贴,还是把它封装一下比较好,在CommonCode中,用Logger封装了日志的相关功能,如下:

public class Logger
{
	public static void Init(string ConfigFile)  
	{
		log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(ConfigFile));
	}
	public static void WinFormInit()  //WinForm程序的初始化
	{
		log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(System.Windows.Forms.Application.StartupPath + "\\log4net.config"));
	}
	public static void WebInit()  //WinForm程序的初始化
	{
		log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(System.Web.HttpContext.Current.Server.MapPath("~")+"\\log4net.config"));
	}
	public static void Debug(String info)
	{
		log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType).Debug(info);
	}
	public static void Info(String info)
	{
		log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType).Info(info);
	}
	public static void Error(String info)
	{
		log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType).Error(info);
	}
	public static void Fatal(String info)
	{
		log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType).Fatal(info);
	}
}

Web的调用还得修改Global.ascx,但WinForm中可以通过WinInit进行初始化了。至于输出信息,则可以通过

CommonCode.Logger.Debug(string)

的形式进行输出。

在CommonCode中,Log4Net是一个通用的输出机制,各种应用的日志输出都需要用它,所以,大多数情况下,需要把Log4Net.dll和CommonCode.dll放在一起。

log4net.config复杂配置

Log4net的输出非常强大,以下是我常用的一些配置:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <log4net>
    <!--按日期输出到Log文件中,不记录错误信息-->
    <appender name="LogAppender" type="log4net.Appender.RollingFileAppender">
      <file value="log/Logs_" />
      <appendToFile value="true" />
      <rollingStyle value="Date" />
      <datePattern value="yyyyMMdd&quot;.txt&quot;" />
      <staticLogFileName value="false" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="[%date{HH:mm:ss}]%message - (%logger)%newline" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="DEBUG" />
        <param name="LevelMax" value="WARN" />
      </filter>
    </appender>
    
    <!--错误日志,保存到一个文件Error.log中-->
    <appender name="ErrorLog" type="log4net.Appender.FileAppender">
      <file value="log/Error.log" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="[%date{yyyy-MM-dd HH:mm:ss}]%message - (%logger)%newline" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="ERROR" />
        <param name="LevelMax" value="FATAL" />
      </filter>
    </appender>
    
    <!--输出到Log2Console,可以实时跟踪查看-->
    <appender name="ToLog2Console" type="log4net.Appender.UdpAppender">
      <param name="Encoding" value="utf-8" />
      <param name="RemoteAddress" value="127.0.0.1" />
      <param name="RemotePort" value="8003" />
      <layout type="log4net.Layout.XmlLayoutSchemaLog4j" />
    </appender>

    <root>
      <level value="ALL" />
      <appender-ref ref="LogAppender" />
      <appender-ref ref="ErrorLog" />
      <appender-ref ref="ToLog2Console" />
    </root>
  </log4net> 
</configuration>

简单说明如下:

  • LogAppender:输出Debug到Warn的信息,存储在log文件下Log_时间戳.txt中,并且会随着文件的增加主动分割
  • ErrorLog:只输出错误信息
  • ToLog2Console:通过UDP向网络发送日志,可以同Log2Console等来接收

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java帮帮-微信公众号-技术文章全总结

day03.集群部署zookeeper【大数据教程】

day03.集群部署zookeeper【大数据教程】 一、Nginx/keepalived/lvs的介绍 1. nginx 1.1. nginx简介 Ngin...

48680
来自专栏pangguoming

Git可视化教程——Git Gui的使用

在Git简介一文中已经对Git进行了简单的介绍,但是理论知识过于枯燥,加上本人专业知识不够扎实,使得初学者在Git的使用上还是会有很大的困难。虽然我更推荐使用G...

31330
来自专栏大数据架构

深入浅出Zookeeper(二) 基于Zookeeper的分布式锁与领导选举

28260
来自专栏即时通讯技术

SSE技术详解:一种全新的HTML5服务器推送事件技术

一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询、Comet技术、We...

18240
来自专栏Janti

记一次内存溢出的分析经历——thrift带给我的痛orz

说在前面的话 朋友,你经历过部署好的服务突然内存溢出吗? 你经历过没有看过Java虚拟机,来解决内存溢出的痛苦吗? 你经历过一个BUG,百思不得其解,头发一根一...

53180
来自专栏三丰SanFeng

redis主从集群搭建及容灾部署(哨兵sentinel)

Redis也用了一段时间了,记录一下相关集群搭建及配置详解,方便后续使用查阅。 提纲 l Redis安装 l 整体架构 l Redis主从结构搭建 l Redi...

53150
来自专栏月色的自留地

golang子进程的启动和停止,mac与linux的区别

28350
来自专栏耕耘实录

使用awk命令批量删除指定范围的账号

版权声明:本文为耕耘实录原创文章,各大自媒体平台同步更新。欢迎转载,转载请注明出处,谢谢

10430
来自专栏Vamei实验室

Linux信号基础

Linux进程基础一文中已经提到,Linux以进程为单位来执行程序。我们可以将计算机看作一个大楼,内核(kernel)是大楼的管理员,进程是大楼的房客。每个进程...

26550
来自专栏Ryan Miao

CentOS6.5网络设置

CentOS6.5网络设置 不知道哪里做错了,长时间无法连接网络,百度了各种还是不可以。最后自己提取了以前可以联网的配置粘贴过来,成功。配置文件内容如下: vi...

36970

扫码关注云+社区

领取腾讯云代金券