本文地址 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. ajax jquery校验用户是否已经注册

    服务端代码这里就不贴了 html代码比较简单,需要自行引入jquery库 <body> 请输入用户名:<input type="text" id="us ...

  2. OpenLayers基础知识:

     OpenLayers是一个开源的js框架,用于在您的浏览器中实现地图浏览的效果和基本的zoom,pan等功能.OpenLayers支持的地图来源 包括了WMS,GoogleMap,KaMap,MSV ...

  3. session.setAttribute和session.getAttribute

    网上搜了些资料 ----------------------------------------------------------------------------- B/S架构中,客户端与服务器 ...

  4. java类的初始化的默认值

    转自:http://blog.csdn.net/abc5382334/article/details/18254517 对于类的成员变量   不管程序有没有显示的初始化,Java  虚拟机都会先自动给 ...

  5. Spring AOP依赖包

    Spring4和2.5发生了很大的变化,原来的spring2.5很多倚赖的jar包都是随着spring一起发布的,现在spring4已 经不再发布倚赖包,需要你自己去导入 1.org.springfr ...

  6. Docker企业级仓库Harbor的安装配置与使用

    Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全.标识和管理等,扩展了开源Docker Distribution.作为一个企业级 ...

  7. php中函数preg_match或preg_match_all 第三个参数$match的解释

    理解自:http://www.cnblogs.com/vicenteforever/articles/1623137.html php手册中是这样解释的 matches 如果提供了参数matches, ...

  8. collision weaknesses

    15.1. hashlib — Secure hashes and message digests — Python 3.5.6 documentation https://docs.python.o ...

  9. NAT STURN,ICE

    NAT原理与NAT穿越 最近在看东西的时候发现很多网络程序中都需要NAT穿越,特意在此总结一下. 先做一个约定: 内网A中有:A1(192.168.0.8).A2(192.168.0.9)两用户 网关 ...

  10. ubuntu 安装搜狗

    先按照这个选择fcitx: https://blog.csdn.net/qq_40563761/article/details/82664851 然后重启 右上角会出现键盘图片点击选configura ...