Log4js原理解析

基于log4js 0.6.14版本

Log4js总共三篇博客

《Log4js原理解析》http://write.blog.csdn.net/postedit/42844085

《Log4js配置详解》http://blog.csdn.net/hfty290/article/details/42843737

《Log4js多进程陷阱与避免》http://blog.csdn.net/hfty290/article/details/42843303

一、概述

网络上有不少关于Log4j的源码解析文章,但是到目前为止还未见到一个log4js的源码解析,虽然这两者有其共同之处,但是在实现原理是存在显著的差别。作为在node.js世界里最流行的日志模块,了解其内部设计与实现还是挺有意义的。本篇将描述log4js的架构与实现,先简要说明log4js中出现的元素,接着为每个元素做详细说明,最后分析元素的协同工作。

二、设计元素简述

在log4js中出现的设计元素包括:level、layout、appender、logger;请看下面表格:

三、色彩缤纷的Appender

不同的Appender实现不同的日志写入方式,所有的Appender都在源码的 lib/appenders目录下,目前log4js提供了很多种的写入方式,有file、datefile、multiprocess、console、clustered、gelf、hookio、loggly、smtp。本文将依次介绍前五种Appender。每个Appender的js文件都会导出appender和configure两个函数,file与dateFile还会导出shutdown函数。

appender函数返回的是一个闭包函数,该闭包函数实现将内容写入到日志。典型的appender函数实现如下:

function fileAppender (file, layout, logSize, numBackups) {
       …….
       var logFile = openTheStream(file, logSize, numBackups);
return function(loggingEvent) {
  logFile.write(layout(loggingEvent) + eol, "utf8");
};
}

而configure函数根据参数提供配置信息,去调用对应的appender函数,将appender函数的返回值作为自己的返回值,如下:

function configure(config, options) {
  ……
  return fileAppender(config.filename, layout, config.maxLogSize, config.backups);
}

因此configure返回值是一个闭包函数,通过该函数可以实现将日志写入到文件之中。

下面将依次介绍每个Appender的实现:

1、file:实现将日志写入到文本文件之中,同时支持日志文件按照大小滚动。

2、datefile:实现将日志写入到文本文件之中,日志按照日期进行滚动。

3、console:实现将日志写入到控制台。

4、multiprocess:实现多进程同步方式写日志,具体是在master(自主配置)进程上开启一个监听端口,所有的worker进程将日志通过tcp发送给master,由master将日志写入到文件中。注意:这种模式只支持配置一个appender,不能配置多个。

Master配置参数:

Worker配置参数:

5、clustered:用于node的cluster环境之中,实现方式与multiprocess类似,真正的写日志是在Master中,Worker只是将日志发送给Master。Worker和Master的配置一样,内部根据cluster.isMaster可以自动判断。

配置参数:

四、布局Layout

Layout实现每条日志记录的格式化,log4js提供了多种的格式化样式可供选择,有basicLayout、messagePassThroughLayout、patternLayout、colouredLayout、coloredLayout,默认情况下会使用basicLayout。所有的Layout都在源码的lib/layouts.js中定义。layouts.js文件除了导出上述说到的这些Layout,还导出一个layout函数,定义如下:

layout: function(name, config) {
    return layoutMakers[name] && layoutMakers[name](config);
}

layoutMakers = {
  "messagePassThrough": function() { return messagePassThroughLayout; },
  "basic": function() { return basicLayout; },
  "colored": function() { return colouredLayout; },
  "coloured": function() { return colouredLayout; },
  "pattern": function (config) {
    return patternLayout(config && config.pattern, config && config.tokens);
  }
}
实现将一个文本描述的Layout转换成内部定义的Layout函数。使用起来就像这样:
layout = layouts.layout(config.layout.type, config.layout);
其中的config.layout.type字段表示Layout的名称,而config.layout中的其他字段为对应Layout的配置信息。只有创建pattern类型的Layout时才需要其他配置。

下面依次介绍每种Layout的功能。

1、basicLayout:最基础的Layout,一个message通过该basicLayout会变成如下样子:

[startTime] [logLevel] categoryName - message\n

2、colouredLayout、coloredLayout:格式化日志内容,其中包括了颜色信息,颜色是根据每条日志的级别预定义的。每条记录内容与basicLayout一样:

[startTime] [logLevel] categoryName - message\n

3、messagePassThroughLayout:日志内容只包括消息,没有其他字段:

message\n

4、patternLayout:实现日志按照配置进行格式化,该Layout需要两个参数,pattern、tokens;其中的pattern表示格式化字符串,tokens表示自定义函数。

预定义格式化有:

  var replacers = {
    'c': categoryName,
    'd': formatAsDate,
    'h': hostname,
    'm': formatMessage,
    'n': endOfLine,
    'p': logLevel,
    'r': startTime,
    '[': startColour,
    ']': endColour,
    '%': percent,
    'x': userDefined
  };

例如,一个patternLayout的配置如下:

"pattern": "%[%r (%x{pid}) %p %c -%] %m%n",

"tokens": {

"pid" : function() { return process.pid; }

}

其中自定义了tokens为pid,通过%x{pid}来引用。注意pattern的的 %[ 与 %] 表示颜色的开始于结束。上述配置打印出来的日志如下:

18:13:39 (19556) INFO app - Test log message

五、Logger对象

Logger对象实现对日志Level的管理,并定义了对外的写日志接口。客户端通过log4js.getLogger()获取的就是该Logger对象。Logger类从events.EventEmitter继承,因此Logger对象具有发生事件的能力。在log4js之中,写日志是通过在log事件上注册对应的appender来实现的。

Logger对象的组成:

六、log4js

log4js源码文件为lib/log4js.js,里面包含了一些函数来实现对appender的加载,日志的管理等操作。所有外面要使用log4js中的对象,都采用export的方式导出,可以直接引用,导出的成员如下:

1、日志管理

log4js中为日志进行类别划分,每个类别下最多可以创建一个Logger。同样每个appender实例也有归属的类别,但是一个appender实例可以同时属于多个类别。如图1:

图1:有两个category分别为cheese与bread;每个category最多对应着一个logger对象。图中有三个appender,cheese.log与cheese1.log类型为file,另外还有一个console。console这个appender同时指向了cheese和bread,也就是这两个日志都会使用到console。另外cheese有三个appender指向它,意味着,如果想cheese分类的日志中写日志,会同时向三个地方写入,cheese.log, cheese1.log, console.

2、log事件

前面已经说明,调用Logger实例的写日志操作,会触发log事件。appender在log事件中被调用,从而实现记录写入到日志文件中。如图1中类型为Cheese的Logger,关联着三个appender实例,fileAppender-cheese.log,fileAppender-cheese1.log,console。那么当调用该logger写日志函数,如logger.info时,触发了log事件,与其关联的三个appender实例被调用,最终这条日志内容被写入到三个地方。

图2:Logger的事件监听机制;用户在调用logger.info(‘hello‘); 触发了Logger实例的log事件,所有类别为Cheese的Appender实例(有三个),都会监听到该事件,实现将日志记录写入到三个位置。另外还有一种为all的分类,如果指定一个appender的类型为all,那么将收到所有logger的log事件,log4js默认加载的console就是类型为all的appender。

3、替换console

在开发的过程中,为了方便可能直接将日志直接以console.log方式打印出来,使用log4js可以将console的日志重定向到日志文件中。log4js导出了两个函数:

4、日志配置定期检查更新

log4js提供了自动重新加载日志配置,更新所有的appender与日志级别的信息,是一项非常使用的功能。log4js导出的configure函数中,第二个参数如果设置了reloadSecs,则会在指定的间隔秒数之后,重载配置。如下:

log4js.configure('file.json', { reloadSecs: 300 });

5、其他导出函数说明

Log4js总共三篇博客

《Log4js原理解析》http://write.blog.csdn.net/postedit/42844085

《Log4js配置详解》http://blog.csdn.net/hfty290/article/details/42843737

《Log4js多进程陷阱与避免》http://blog.csdn.net/hfty290/article/details/42843303

时间: 2024-11-03 20:59:55

Log4js原理解析的相关文章

MyBatis框架中Mapper映射配置的使用及原理解析(七) MapperProxy,MapperProxyFactory

从上文<MyBatis框架中Mapper映射配置的使用及原理解析(六) MapperRegistry> 中我们知道DefaultSqlSession的getMapper方法,最后是通过MapperRegistry对象获得Mapper实例: public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory =

Android中微信抢红包插件原理解析和开发实现

一.前言 自从去年中微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导致了.或许是网络的原因,而且这个也是最大的原因.但是其他的不可忽略的因素也是要考虑到进去的,比如在手机充电锁屏的时候,我们并不知道有人已经开始发红包了,那么这时候也是让我们丧失了一大批红包的原因.那么关于网络的问题,我们开发者可能用相关技术无法解决(当然在Google和Facebook看来的话,他们

MyBatis框架中Mapper映射配置的使用及原理解析(三) 配置篇 Configuration

从上文<MyBatis框架中Mapper映射配置的使用及原理解析(二) 配置篇 SqlSessionFactoryBuilder,XMLConfigBuilder> 我们知道XMLConfigBuilder调用parse()方法解析Mybatis配置文件,生成Configuration对象. Configuration类主要是用来存储对Mybatis的配置文件及mapper文件解析后的数据,Configuration对象会贯穿整个Mybatis的执行流程,为Mybatis的执行过程提供必要的配

MyBatis框架中Mapper映射配置的使用及原理解析(二) 配置篇 SqlSessionFactoryBuilder,XMLConfigBuilder

在 <MyBatis框架中Mapper映射配置的使用及原理解析(一) 配置与使用> 的demo中看到了SessionFactory的创建过程: SqlSessionFactory sessionFactory = null; String resource = "mybatisConfig.xml"; try { sessionFactory = new SqlSessionFactoryBuilder().build(Resources .getResourceAsRea

Spring Boot启动原理解析

Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘. 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 从上面代码可以看出,Annotation定义(@Sp

游戏外挂原理解析与制作 - [内存数值修改类 篇一]

本章旨在讲解外挂实现原理,未深入涉及至代码层面.希望能与对这方面感兴趣的朋友多多交流,毕竟理论是死的,套路是固定的,只有破解经验是花大量时间和心血积累的. 对于单机游戏而言,游戏中绝大部分的参数(比如血.蓝.能量亦或是金币)都存储在计算机的堆栈中,一些类似剧情进度的则加密后写入本地的自定义配置文件中: 对于页游.网游和手游,虽然服务器保存了大量的重要的参数,但由于客户端不可避免的需要进行大量的计算和资源的加载,本地内存种必定存有部分的临时变量,通过判断这些变量的变化规律和函数的破密寻到利于自身的

JSONP跨域的原理解析

JSONP跨域的原理解析 一种脚本注入行为 在 2011年10月27日 那天写的     已经有 99238 次阅读了 感谢 参考或原文 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容. JavaScript这个安全策略在进

经典CSS实现三角形图标原理解析

前言: 在写这篇文章之前,我也看过很多前端大神写的代码,But,都只是粘贴代码和给出显示效果,对于初学者来说大家都喜欢刨根问底,为什么要这样做呢? 接下来就让我给大家分享一下我对CSS实现三角形的理解: border边框语法: border 四条边框设置 border-left 设置左边框,一般单独设置左边框样式使用 border-right 设置右边框,一般单独设置右边框样式使用 border-top 设置上边框,一般单独设置上边框样式使用 border-bottom 设置下边框,一般单独设置

Request 接收参数乱码原理解析二:浏览器端编码原理

上一篇<Request 接收参数乱码原理解析一:服务器端解码原理>,分析了服务器端解码的过程,那么浏览器是根据什么编码的呢? 1. 浏览器解码 浏览器根据服务器页面响应Header中的“Content-Type: text/html; charset=gb2312”解码.修改web.config中“responseEncoding=utf-8”,发现服务器页面响应Header变成了“Content-Type: text/html; charset=utf8”. <system.web&g