本文地址 http://www.cnblogs.com/jasonxuli/p/6518650.html
 
log4js
 
版本 0.6.16, 最新版1.1.1 大体类似。
 
使用 log4js 时,基本的流程是:
1,声明 config 配置;
2,log4js.configure(config);
3, log4js.getLogger(categoryName);
 
配置
 
主要有下面几个要点:
 
type: 表明 appender 的类型,对应 log4js/lib/appenders/ 目录下的文件名, log4js 会在加载配置文件时根据 type 加载对应文件。
     categoryFilter.js, clustered.js, console.js, dateFile.js, file.js, fileSync.js, gelf.js, hookid.js, loggly.js, logLevelFilter.js, multiprocess.js, smtp.js
          
category:表明 appender 的分类,用户自定义;如果不指定,加载时默认值为 [all];相同 category 的 appender 会被添加到内部变量 appenders {category : appender} 中。这个 appenders 的作用体现在之后通过 getLogger() 获取 logger 时;
 
level: log4js 的 level 如下
module.exports = {
ALL: new Level(Number.MIN_VALUE, "ALL"),
TRACE: new Level(5000, "TRACE"),
DEBUG: new Level(10000, "DEBUG"),
INFO: new Level(20000, "INFO"),
WARN: new Level(30000, "WARN"),
ERROR: new Level(40000, "ERROR"),
FATAL: new Level(50000, "FATAL"),
OFF: new Level(Number.MAX_VALUE, "OFF"),
toLevel: toLevel
};
appender 结构:参看下面的示例,简单类型例如 file,fileSync等,只需要简单的对象,不需要内部再嵌套一个 appender; 对于复杂类型例如 logLevelFilter,categoryFilter等,最终还是需要一个简单类型去写日志,因此需要嵌套一个 appender 。
 
var config = {
appenders : [
{
type: "console"
},
{
type : "file",
filename: "/var/log/kernel/test.log"
},
{
type : "logLevelFilter",
level : "ALL",
appender: {
type : "file",
filename: "/var/log/kernel/kernel.log",
layout:{
type:"pattern",
pattern: "[%h %x{pid}] - [%d] [%p] %c %m",
tokens: {
pid: function(){return process.pid}
}
}
}
},
{
type : "logLevelFilter",
level : "ERROR",
appender: {
type : "file",
filename: "/var/log/kernel/kernelerr.log"
}
},
{
type : "file",
filename: "/var/log/kernel/cron.log",
category: "cron"
},
{
type : "file",
filename: "/var/log/kernel/mem.log",
category: "memory"
}
],
replaceConsole: true
}; log4js.configure(config);
 配置加载流程
 
根据log4js.js 中的代码次序,关键的函数是下面几个 : 
 
1,configure() : 
      入口函数
 
2,loadAppender(appender, appenderModule) :
     根据 type 加载 log4js/lib/appenders/ 目录下对应的 appender 模块;之后调用该模块的 configure() 加载该 appender 配置,返回最终负责写 log 的函数 function(loggingEvent); 因此 logLevelFilter 这样的"高级"模块就会寻找 config.appender 属性进行后续配置;
 
3,addAppenderToCategory(appender, category)
     将 category 和加载后的 appender 作为键值对添加到 appenders 对象;
 
4,addAppenderToAllLoggers(appender)
     将没有指定 category 的 appender 默认为 [all],添加到 logger 缓存对象 loggers 中; 
 
其实不太明白这里为什么要先添加 [all] 到 loggers 缓存中,毕竟 getLogger() 函数中 categoryName 的默认值是 [default];为什么不统一都用 [default] 或者 [all],至少相当于预热缓存了。
     
 
logger和appender的关系
 
主要体现在下面的函数中:
function getLogger (categoryName) {

  // Use default logger if categoryName is not specified or invalid
if (typeof categoryName !== "string") {
categoryName = Logger.DEFAULT_CATEGORY;
} var appenderList;
if (!hasLogger(categoryName)) {
// Create the logger for this name if it doesn't already exist
loggers[categoryName] = new Logger(categoryName);
if (appenders[categoryName]) {
appenderList = appenders[categoryName];
appenderList.forEach(function(appender) {
loggers[categoryName].addListener("log", appender);
});
}
if (appenders[ALL_CATEGORIES]) {
appenderList = appenders[ALL_CATEGORIES];
appenderList.forEach(function(appender) {
loggers[categoryName].addListener("log", appender);
});
}
} return loggers[categoryName];
}

其中,loggers 和 appenders 上面说过,一个是是 logger 的缓存map; 一个是 appender 的Map。

 
getLogger(categoryName)步骤如下:
1,先去 loggers 中以 categoryName 为 key 找 logger,找到就直接返回,没有找到就生成一个 new Logger(categoryName),并添加到 logger 缓存。 
2,在 appenders 中以 categoryName 为key 查找 appenderList,找到了就以该 logger 为宿主,将 appenderList 中所有的 appender 添加为 on 事件的监听器。
3,不管2是否成功,都将 appenders 中 [all] 对应的所有 appender 添加为该 logger 的 on 事件的监听器。
 
最终两个Map的结构大致如下:
 
appenders : 
[all]            ->  [apd1, apd2, ...]
category1    ->  [apd3]
category2    ->  [apd4, apd5]
...
 
loggers : 
[all]            ->  loggerA      --addListener()-->  [apd1, apd2, ...]
[default]     ->  loggerB      --addListener()-->  [apd1, apd2, ...]
category1   ->  loggerC      --addListener()-->  [apd3, apd1, apd2, ...]
category2   ->  loggerD      --addListener()-->  [apd4, apd5, apd1, apd2, ...]
...
 
 
因此:
1,category 一样的 appender 会同时输出日志;
2,没有指定 category 的 appender 总是会输出日志;

Log4js 工作原理及代码简析的更多相关文章

  1. OpenStack之虚机冷迁移代码简析

    OpenStack之虚机冷迁移代码简析 前不久我们看了openstack的热迁移代码,并进行了简单的分析.真的,很简单的分析.现在天气凉了,为了应时令,再简析下虚机冷迁移的代码. 还是老样子,前端的H ...

  2. jdk1.8 ConcurrentHashMap 的工作原理及代码实现,如何统计所有的元素个数

    ConcurrentHashMap 的工作原理及代码实现: 相比于1.7版本,它做了两个改进 1.取消了segment分段设计,直接使用Node数组来保存数据,并且采用Node数组元素作为锁来实现每一 ...

  3. JAVA NIO工作原理及代码示例

    简介:本文主要介绍了JAVA NIO中的Buffer, Channel, Selector的工作原理以及使用它们的若干注意事项,最后是利用它们实现服务器和客户端通信的代码实例. 欢迎探讨,如有错误敬请 ...

  4. Java三大器之过滤器(Filter)的工作原理和代码演示

    一.Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术之一,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp,Servlet, 静 ...

  5. ConcurrentHashMap 的工作原理及代码实现

    ConcurrentHashMap采用了非常精妙的"分段锁"策略,ConcurrentHashMap的主干是个Segment数组.Segment继承了ReentrantLock,所 ...

  6. HashMap 的工作原理及代码实现,什么时候用到红黑树

    HashMap工作原理及什么时候用到的红黑树: 在jdk 1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里.但是当位于一个桶中的元素较多,即has ...

  7. WinForm 自动完成控件实例代码简析

    在Web的应用方面有js的插件实现自动完成(或叫智能提示)功能,但在WinForm窗体应用方面就没那么好了. TextBox控件本身是提供了一个自动提示功能,只要用上这三个属性: AutoComple ...

  8. Java三大器之监听器(Listener)的工作原理和代码演示

    现在来说说Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次, ...

  9. uboot 2013.01 代码简析(3)第二阶段初始化

    u-boot第二阶段初始化内容的入口函数是_main,_main位于arch/arm/lib/crt0.S文件中: _main函数中先为调用board_init_f准备初始化环境(设置栈指针sp和并给 ...

随机推荐

  1. CocoaPods的 安装 /卸载/升级

    CocoaPods用来管理第三方框架 Mac 安装 Cocoapods 导引如果你的 Mac OSX 升级到 10.11.x+, 并且需要安装 Cocoapods, 可以参考本博客.安装 rubyMa ...

  2. FTP新建文件夹访问

    今天在远程服务器上添加了文件夹,本来还想着FTP打开看看,结果竟然发现没有这个文件夹访问 想了一下,感觉应该是FTP访问的文件设置,只有FTP设置了的文件夹才能有显示

  3. poj_3352 连通图的桥

    题目大意 给定N个点,他们之间用一些双向边连通,使得这N个点两两相互可达.但是其中某些双向边为桥,这样若断开这些桥,则整个图就无法做到点之间两两可达.现在可以添加若干条双向边,使得断开图中的任意一条边 ...

  4. Android 7.1.1 系统截屏

    frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java Tak ...

  5. 传智播客微金所项目实战移动web开发

    1.源码笔记 我的源码+笔记(很重要):链接: http://pan.baidu.com/s/1kULKqcJ 感谢传智播客项目相关视频:1.6天 链接: https://pan.baidu.com/ ...

  6. 用了快1年的MacBook Pro遇到的硬件问题

    去年11月7日买的MacBook Pro,到目前快1年了,遇到了3个硬件问题(之前用了5年的Thinkpad在5年内未出现任何硬件问题): 1. 有一次MacBook放在背包中,背包拎在手上落在地上, ...

  7. explain 分析 聚合统计语句的性能

    EXPLAIN SELECT COUNT(1) FROM question; id select_type table partitions type possible_keys key key_le ...

  8. network command assistant

    这篇文章收集了久经考验靠谱的命令,也收集了几个比较新的命令.多数命令都可以在图形桌面执行,即使是没什么终端使用经验的Linux用户也会常常执行命令来使用ping或是其它的网络诊断工具. 1.curl ...

  9. html中使用JS实现图片轮播效果

    1.首先是效果图,要在网页中实现下图的轮播效果,有四张图片,每张图片有自己的标题,然后还有右下角的小方框,鼠标悬浮在小方框上,会切换到对应的图片中去. 2.先是HTML中的内容,最外层是轮播图整个的容 ...

  10. python采用pika库使用rabbitmq总结,多篇笔记和示例(转)

    add by zhj:作者的几篇文章参考了Rabbitmq的Tutorials中的几篇文章. 原文:http://www.01happy.com/python-pika-rabbitmq-summar ...