一、log4j的简介
log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们可以控制每一条日志的输出格式:通过定义每一条日志信息的级别,能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活的进行配置,而不需要修改应用的代码。
二、Log4j组件介绍
Log4j主要由Loggers(日志记录器)、Appenders(输出控制器)和Layout(日志格式化器)组成。其中Loggers控制日志的输出以及输出级别;Appender指定日志的输出方式(输出到控制台、文件等);Layout控制日志信息的输出格式。
1. Loggers日志记录器
日志记录器,负责手机处理日志记录,实例的命名就是类的权限定名,如com.atredhorse.eduservice.EduTeacher,Logger的名字大小写敏感,其命名有继承机制;例如:name为com.atredhorse.eduservice的logger会继承name为com.atredhorse。Log4j中有一个特殊的logger叫做"root",它是所有logger的根,也就意味着其他所有的logger都会直接或者间接的继承自root。root logger可以用Logger.getRootLogger()方法获取。
关于日志级别信息,例如DEBUG、INFO、WARN、ERROR...级别是分大小的,DEBUG<INFO<WARN<ERROR,分别用来指定这条日志信息的重要程度,Log4j输出日志的规则是:只输出级别不低于设定级别的日志信息,假设Loggers级别设定为INFO,则INFO、WARN、ERROR级别的日志信息都会输出,而级别比INFO低的DEBUG则不会输出。
2. Appenders
记录日志以及定义日志的级别仅仅是Log4j的基本功能,Log4j日志系统还提供许多强大的功能,比如允许把日志输出到不同地方,比如控制台(Console)、文件(Files)等,可以根据天数或者文件大小产生新的文件,可以以流的形式发送到其他地方等等。
常用Appenders:
ConsoleAppender:将日志输出到控制台
FileAppender:将日志输出到文件中
DailyRollingFileAppender:将日志输出到一个日志文件,并且每天输出到一个新的文件
RollingFileAppender:将日志信息输出到一个日志文件,并且指定文件的尺寸,当文件大小达到指定尺寸时,会自动把文件改名,同时产生一个新的文件。
JDBCAppender:将日志信息保存到数据库中。
3. Layouts日志输出格式
Log4j可以在Appender的后面附加Layouts来完成格式化日志的输出。Layouts提供四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。
常用Layouts:
HTMLLayout:格式化日志输出为HTML表格形式
SimpleLayout:简单的日志输出格式化,打印的日志格式如默认INFO级别的消息。
PatternLayout: 最强大的格式化组件,可以根据自定义格式输出日志,如果没有指定转换格式,就是用默认的转换格式。
4. Layouts日志输出格式说明
使用PatternLayout可以自定义格式输出,是我们最常用的方式。
这种格式化输出采用类似于C语言的printf函数的打印格式格式化日志信息,具体的占位符及其含义如下:
%m 输出代码中指定的日志信息
%p 输出优先级,及DEBUG、INFO等
%n 换行符(Windows和Unix平台的都是换行符为"\n")
%r 输出自应用启动到输出该log信息耗时费的毫秒数
%c 输出打印语句所属的类的全名
%t 输出产生该日志的线程全名
%d 输出服务器当前时间,默认为ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss}
%l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。
%F 输出日志消息产生时所在的文件名称
%L 输出代码中的行号
%% 输出一个“%”
三、源码分析org.apache.log4j.Logger.getLogger()
1. 日志管理器
进入org.apache.log4j.Logger.getLogger(),会看到代码LogManager.getLogger(clazz.getName()),而LogManager就是log4j的日志管理器。
LogManager类中包含了不同形式(后缀名不同)的配置文件,而最常用的配置文件就是log4j.propreties属性文件(语法简单,使用方便)。
2. log4j.propreties加载时机
LogManager的静态代码快static中,可以找到Loader.getResource("log4j.properties"); 这行代码的最大的一个提示信息就是系统默认要从当前的类路径下找到log4j.properties。对于项目是maven工程,那么理应在resources目录下。
3. 加载完成后配置文件是如何读取的
继续在LogManager的静态代码块中查找,在url != null时,OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository());这行代码就是作为属性文件的加载,执行响应的properties配置对象configurator = new PropertyConfigurator();
进入到PropertyConfigurator类中,观察到里面的常量信息,这些常量信息就是在properties属性文件中的各种属性配置项。其中,我们看到了如下两项信息是必须要进行配置的。
static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger"; static final String APPENDER_PREFIX = "log4j.appender.";
通过代码:String prefix = "log4j.appender." + appenderName;可以看到需要自定义一个appenderName。我们可以起名为consoleAppender。配置文件的key就是log4j.appender.consoleAppender,而取值就是log4j中为我们提供的appender类。
例如:log4j.appender.consoleAppender = org.apache.log4j.ConsoleAppender
在appender输出过程中,我们还可以指定输出的格式
String layoutPrefix = prefix + ".layout";
完整配置就是log4j.appender.consoleAppender.layout = org.apache.log4j.SimpleLayout
通过log4j.rootLogger继续在类中搜索,找到方法this.parseCategory。进入此方法,有代码
StringTokenizer st = new StringTokenizer(value, ",");表示要以逗号的方式切割字符串,证明了log4j.rootLogger的取值,其中可以有多个值,使用逗号可以分割。
通过代码String levelStr = st.nextToken();表示切割后的第一个值是日志的级别。
通过代码while(st.hasMoreTokens()) 表示接下来的第2~n个值,配置的就是appenderName.证明了配置的方式:log4j.rootLogger=日志级别,appenderName1,appenderName2,,,.
表示可以同时在根节点配置多个输出的路径。
四、log4j.properties的简单配置
经过源码分析,可以配置最简单的log4j.properties。
#根logger
log4j.rootLogger=info,consoleAppender
#配置appender输出格式,其中consoleAppender是自定义的appender的名字
log4j.appender.consoleAppender = org.apache.log4j.ConsoleAppender
#配置输出格式
log4j.appender.consoleAppender.layout=org.apache.log4j.SimpleLayout