log4net面面观之工作原理
转自:逗逼的博客:http://itrust.cnblogs.com/archive/2005/01/25/97225.html
要知道Log4net究竟是咋干活的,咱们可以从下面这个脉络简图入手。你的程序中的语句log4net.LogManager.GetLogger().Info(“hello world!”); 就会引发log4net如下内部工作流程。不要管上面的对象(Appender/Filter等等)是什么东东,先看着这个流程,我们来摸摸log4net工作的脉络,然后我们再按关节一一打通。
1. 第一件事就是找调度(LogManager)要个干活的工人(Logger,写日志的对象),当然,方法是调用LogManager.GetLogger()。找个什么样工人,究竟是那个工人会被挑中,这里面有些曲折,会涉及到Repository(高级话题,下回分解)。咱先不管这么多,知道有个能干活的工人(Logger) 肯定是被找来了。
另外有些麻烦事儿,这工人有经纪人ILoggerWrapper(Logger需要实现ILogger, 而ILoggerWrapper唯一的方法就是得到ILogger实例),经纪人又有代理ILog(ILog继承于ILoggerWrapper)。代理ILog存在的意义在于给你提供方便的接口函数(Info,Warn等等),而不是工人提供的void Log(string callerFullName, Level level, object message, Exception t)。 不管关系多复杂,虽然你让干什么活都得先对代理说,但最后还都是告诉了工人,一个字也没落。
2. 你通过Info(“hello”)告诉工人干活了,工人Logger一定先看看这事能不能干。你的配置里说只写Info这个级别以上的信息,咱就不能写Debug和Warn。这种情况你需要付出性能代价(一个函数调用和一个整数形式的级别比较)。然后,工人Logger就创建一个任务包LoggingEvent,把你要做的事儿用任务包的形式包起来,以后的流程就都针对任务包LoggingEvent处理了。
任务包LoggingEvent里信息丰富,包含:时间代码位置、工人的名字、信息、线程名、用户名、信息、异常、上下文等等。
3. 接下来,Appender们登场了。原来工人自己不干具体的活,手里拽着一堆马仔,自己成了工头,告诉Appender去DoAppend(),让马仔们干活。注意,这里说得是“马仔们”,就是说同时会有多个马仔都在写东东。究竟那些马仔能被选中完成这光荣的任务,还要由客户您来决定,如:<appender-ref ref="ConsoleAppender" />
这些马仔及其特长:
|
马仔 |
特长 |
|
ConsoleAppender |
在控制台上写日志 |
|
ColoredConsoleAppender |
ConsoleAppender的徒弟,青出于蓝,写出来的东东还可以带颜色,花花绿绿的,煞是好看 |
|
FileAppender |
往文件里写日志 |
|
RollingFileAppender |
往可滚动的文件里写日志,就是说它会按客户要求控制文件大小和数量,一个文件写满就帮你再开另一个接着写 |
|
ForwardingAppender |
帮其他Appender传任务包的人,当然自己可以干一点雁过拔毛的事(做一些过滤的事情,比如说你要写的东东里包含不雅的词汇,它可以让你变得文明一些) |
|
NetSendAppender |
往Windows的Messager写日志 |
|
ASPNetTraceAppender |
在Asp.Net的Trace里写日志 |
|
ADONetAppender |
往数据库里写日志 |
|
EventLogAppender |
往Windows事件里写日志 |
|
RemotingAppender |
把日志转给另外的Remoting服务,如:一个专门的集中的日志服务器 |
|
SmtpAppender |
通过邮件把日志发出去 |
|
SmtpPickupDirAppender |
把日志包成邮件,发在指定目录,等待专门的Smtp代理去发送 |
|
TelnetAppender |
把日志发到Telnet控制台 |
|
UdpAppender |
通过UDP协议把日志发给另外的一个主机,或者组播给一些主机 |
当然,你可以自己搞个马仔,比如发个短信什么的,可以取名叫MobilePagerAppender(从AppenderSkeleton继承),通过配置告诉log4net就行。
4. 说到这儿,检查员Filter登场。这活最终究竟干不干,马仔还得通过Decide()再问问检查员们。注意,这里说得是“检查员们”,就是说所有在册的检查员都点头,这话才能干。如何让检查员在册,看配置文件,如:
<appender name="FF" type="log4net.Appender.ForwardingAppender" >
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="DEBUG"/>
<param name="LevelMax" value="INFO"/>
</filter>
<appender-ref ref="ConsoleAppender" />
</appender>
雁过拔毛的马仔ForwardingAppender和检查员LevelRangeFilter配合工作,把大于Debug和小于Info的东东通知给马仔ConsoleAppender,让它写到控制台上。
每个检查员都有自己的关注点,如下:
|
检查员 |
特长 |
|
LevelMatchFilter |
日志级别等于指定的级别才放行 |
|
LevelRangeFilter |
按日志级别范围做比较,可取区间内的放行。如必须大于Warn小于Info |
|
StringMatchFilter |
对你的言论进行检查,符合字符串比对条件的放行。如:必须包含“芝麻开门”的字符串才让写。 比对条件可以是简单的带通配符的字符串,也可以是正则表达式(帅!) |
|
PropertyFilter |
StringMatchFilter的徒弟,对LoggingEvent的某个属性进行检查,符合字符串匹配条件才放行 |
|
LoggerMatchFilter |
检查工头(Logger)的名字,如果是以指定的字符串开头的才放行。如:只要是姓“张”的工头发下来的任务包,都让过。 |
|
DenyAllFilter |
这个检查员最黑,什么都不让过 |
5. 检查员们点头后,这事就必须要干了。怎么干?客户要写的东东究竟用什么格式输出?这活由排版员Layout来干。下面是排版员的名单:
|
排版员 |
特长 |
|
对LoggingEvent中的异常信息message进行排版 |
|
|
最常用的排版员,通过一堆标识符来决定版式。 如:"%date %-5level- %message" 表示要以此输出日志日期、级别(5个字母的宽度)、信息 |
|
|
最简单的版式: [level] - [message] |
|
|
把日志写到XML文件中去,写成一个Element |
|
|
把日志写到XML文件中去,写成一个Element,其格式需符合log4j对事件定义的DTD. |
排版员需要排版LoggingEvent的信息的字符串内容RenderedMessage,例如文章开头的“hello world!”。除了“hello world!”这样的字符串,信息message还可以是任意的对象。因此需要针对对象进行专门的排版,由Render(对象打印机)来干。
你可以针对自己的信息对象搞Render。如打印订单信息的OrderRenader,一旦在订单处理中发生错误,把订单的主要信息打印出来,方便调试。别忘了:OrderRenader必须实现log4net.ObjectRenderer.IObjectRenderer。
6. 一切就绪,各个马仔就做最后的输出,有打印屏幕的,有写文件的,有在网络上发数据的,八仙过海,各显神通。
整个流程走完,相信我们接触到的Logger、Appender、Filter、Layout、Render都已不再陌生。log4net良好的实现了事件过滤、格式排版的高度扩展性和可配置性。
log4net的这处理模式可以看作是一种扩展的Publish/Subscribe模式,完全可以应用到我们自己的应用程序中去,比如说订单处理,可以实现对不同订单的过滤,实现不同的订单的提交目的地(写数据库、发邮件、短信通知等等)。
最后,给出Repository、Appender、Filter、Layout、Render的关系简图:
虽然,Repository在下回分解,但这里还需要简单说两句。Repository可以说成基于一个log4net配置节创建的log4net容器,它根据log4net配置节的指示创建以上其他的对象并保有他们的实例,随时为你所用。一般而言,你的应用程序不需要关心它,用缺省的容器即可。
log4net面面观之工作原理的更多相关文章
- 菜鸟学Struts2——Struts工作原理
在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...
- 【夯实Nginx基础】Nginx工作原理和优化、漏洞
本文地址 原文地址 本文提纲: 1. Nginx的模块与工作原理 2. Nginx的进程模型 3 . NginxFastCGI运行原理 3.1 什么是 FastCGI ...
- HashMap的工作原理
HashMap的工作原理 HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...
- 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)
RAC 工作原理和相关组件(三) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...
- ThreadLocal 工作原理、部分源码分析
1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...
- Servlet的生命周期及工作原理
Servlet生命周期分为三个阶段: 1,初始化阶段 调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...
- 代码管理工具 --- git的学习笔记二《git的工作原理》
通过几个问题来学习代码管理工具之git 一.git是什么?为什么要用它?使用它的好处?它与svn的区别,在Mac上,比较好用的git图形界面客户端有 git 是分布式的代码管理工具,使用它是因为,它便 ...
- 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL
周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...
- 浏览器内部工作原理--作者:Tali Garsiel
本篇内容为转载,主要用于个人学习使用,作者:Tali Garsiel 一.介绍 浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工作原理,我们将看到,从你在地址栏输入google.com到你看到 ...
随机推荐
- 【转】PHP框架性能测试报告 - ThinkPHP 3.2.3 Laravel 5.2 Yii2.0.5
作为一个PHP开发者,而且是初创企业团队的技术开发者,选择开发框架是个很艰难的事情. 用ThinkPHP的话,招聘一个刚从培训机构出来的开发者就可以上手了,但是性能和后期代码解耦是个让人头疼的事情.不 ...
- Nginx 禁用IP IP段
最近公司网站被竞争对手用爬虫频繁访问,所以我们这边要禁止这些爬虫访问,我们通过nginx 指令就可以实现了 方法一:直接在LB机器上封IP 1.在 blocksip.conf 文件中加入要屏蔽的ip或 ...
- Java实验报告二:Java面向对象程序设计
Java实验报告二:Java面向对象程序设计 ...
- 详解 Qt 线程间共享数据(用信号槽方式)
使用共享内存.即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的. Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容.Qt线程间共享 ...
- zepto源码--isEmptyObject,isNumeric,inArray,trim--学习笔记
1.isEmptyObject,判断对象是否为空对象的函数 定义变量name,遍历传入对象的属性name,如果存在任何属性,则返回false,判定传入的参数为非空对象,否则即为空对象. 2.isNum ...
- PushKit和传统长连接方式的比较
iOS and PushKit This post will cover basic concepts for VoIP apps on iOS. I will not post any code ( ...
- window平台安装MongoDB
官网:www.mongodb.org 安装-->设置环境变量-->启动 1.下载: 根据系统下载 32 位或 64 位的 .msi 文件,下载后双击该文件,按提示安装即可, 2.设置安装目 ...
- Magento - Rewrite机制一窥
看一个url例子 http://localhost/magento/index.php/customer/account/login 这里假定http://localhost/magento/ 是ma ...
- SQL Server 用SQL语句查找某个表的触发器
select * from sysobjects where xtype='TR' and parent_obj=object_id('表名') 再用sp_helptext ...
- undefined reference to `switch_dev_unregister'
编译内核时,使用默认的配置进行编译.出现错误:undefined reference to switch_dev_unregister',undefined reference toswitch_se ...