Log4j

Log4j

看了多少篇博客,没有能把Log4j说清楚的,log2j-1.2官网文档

log4j类似的基于配置的日志框架的重要性

官网的意思大概是这样的,说,大概一个项目的的4%的代码是专门做日志的,一个适当大小的项目,可能会有成千上万条关于日志的代码嵌入在项目中,管理项目中的日志都需要耗费大量的精力,管理日志而不需要手动修改嵌入的日志代码,于是log4j应运而生,log4j是为替代System.out.println().

log4j概述

log4j有三大组件,logger,appender,layout。

先上几段Sample,再拿sample细讲。

配置样例 1

##控制台打印
log4j.rootLogger=INFO,Console,fileAppender  
log4j.appender.Console=org.apache.log4j.ConsoleAppender  
log4j.appender.Console.layout=org.apache.log4j.PatternLayout  
log4j.appender.Console.layout.ConversionPattern=%d{yy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n  
log4j.appender.fileAppender=org.apache.log4j.DailyRollingFileAppender  
log4j.appender.fileAppender.File=/Users/Jack/logs/tomcat.log  
log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout  
log4j.appender.fileAppender.layout.ConversionPattern=%d{yyyy.MM.dd HH:mm:ss} %5p %c{1}(%L):? %m%n  
#打印MyBatis信息 错误的配置
log4j.logger.com.ibatis=debug  
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug  
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug  
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug 

配置样例2 来自官网

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout  
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n  

使用样例 来自官网

import com.foo.Bar;

 import org.apache.log4j.Logger;
 import org.apache.log4j.PropertyConfigurator;

 public class MyApp {

   static Logger logger = Logger.getLogger(MyApp.class.getName());

   public static void main(String[] args) {


     // BasicConfigurator replaced with PropertyConfigurator.
     PropertyConfigurator.configure(args[0]);

     logger.info("Entering application.");
     Bar bar = new Bar();
     bar.doIt();
     logger.info("Exiting application.");
   }
 }
Logger

logger是什么?logger就是这个

static Logger logger = Logger.getLogger(MyApp.class.getName());  

每一个logger都有一个名字,而且名字采用了层级策略,具体是什么,马上讲到。每get一次logger就会产生一个logger示例,名字为MyApp的logger是一个logger,样例1(样例1的mybatis是功能上可能错误的,只是个样例而已)最下边是名字为com.ibatis的logger,也是一个logger,名字为com.ibatis.common.jdbc.SimpleDataSource=debug 也是一个logger,这个logger跟com.ibatis是有关系的,com.ibatis.common.jdbc.SimpleDataSource是子logger,com.ibatis是父logger,这就是层级关系,父子关系的logger继承的是什么东西?这又是一个重点,Level和Appender。先说Level,打印log的方法有debug, info, warn, error, fatal还有一个log(level,message).对应的有5个级别,DEBUG < INFO < WARN < ERROR < FATAL,

log4j.rootLogger=DEBUG,Console,fileAppender  

这一条配置的第一个参数DEBUG配置的是根logger级别,rootLogger是所有的logger的父级,(MyApp)logger没有配置level,则继承其最近的父级的level,MyApp是没有"点"分隔的包,它的直接父级就是rootLogger.每一个logger都有名字,有level,如果没有指定level,则继承父级的。然后说,各个打印方法的关系,如果当前logger的级别是INFO,而调用的是logger.debug(),此时因为DEBUG

 logger.setLevel(Level.INFO);

Level继承示例表 现在再来看MyBatis打印sql语句,其实配置部分就是为了细粒度的控制DEBUG信息,别的DEBUG日志不想打出来,因为非常多,非常乱,只打印MyBatis的就好。样例1的mybatis是有问题的,我开始也不懂,从网上抄了好几段,都不太满意,或者不能实现,所以才抠了一会儿英文文档,MyBatis文档,MyBatis的官方是这么写的

log4j.logger.org.mybatis.example.BlogMapper.selectBlog=DEBUG #只打印一个方法的sql  
log4j.logger.org.mybatis.example=DEBUG#打印一个包下所有的sql。  
Appender和Layout
log4j.rootLogger=DEBUG,Console,fileAppender  

Appender是什么?第一参数后边的就是Appender,可以有多个。Appender代表的是一个输出目的地,输出到控制台是一个,输出到文件,还有输出到Currently ,appenders exist for the console, files, GUI components, remote socket servers, JMS, NT Event Loggers, and remote UNIX Syslog daemons
Appender是另外一个重点,重点就是Appender的继承关系。 Appender继承示例表 大概意思说一下,如果我这个Logger添加了一个自己的Appender(可以多个),我的所有输出目标里边我自己的这个Appender肯定会有,如果我的Additivity Flag属性为False,表示我不会继承我的直接父级的Appenders,如果为True,表示我将继承我直接父级的所有Appenders。直接父级的所有Appenders既可以是自己的,可以是继承自他直接父级的。

上一段,强大的XML配置。

log4j.xml 代码来源HeartBeat

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>

    <!--
        Log4j 日志配置
        默认输出到控制台
        一些指定的包的日志记录到 文件中
    -->
    <!--console-->
    <appender name="Console" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %p [%c] - %m%n"/>
        </layout>
    </appender>

    <!-- operation file-->
    <appender name="operationAppender" class="org.apache.log4j.FileAppender">
        <param name="Append" value="true"/>
        <param name="File" value="../logs/heart_beat-operation.log"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %p [%c] - %m%n"/>
        </layout>
    </appender>

    <!--scheduler file appender-->
    <!--<appender name="schedulerAppender" class="org.apache.log4j.FileAppender">-->
    <!--<param name="Append" value="true"/>-->
    <!--<param name="File" value="../logs/heart_beat-scheduler.log"/>-->
    <!--<layout class="org.apache.log4j.PatternLayout">-->
    <!--<param name="ConversionPattern" value="%d %p [%c] - %m%n"/>-->
    <!--</layout>-->
    <!--</appender>-->

    <!--scheduler file daily appender-->
    <appender name="schedulerAppender" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="../logs/heart_beat-scheduler.log"/>
        <param name="Append" value="true"/>
        <param name="DatePattern" value="'.'yyyy-MM-dd'.log'"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %p [%c] - %m%n"/>
        </layout>
    </appender>


    <!--Operation logger -->
    <logger name="com.andaily.service.operation" additivity="false">
        <level value="DEBUG"/>
        <appender-ref ref="operationAppender"/>
    </logger>
    <logger name="com.andaily.domain" additivity="false">
        <level value="DEBUG"/>
        <appender-ref ref="operationAppender"/>
    </logger>

    <!--spring logger-->
    <logger name="org.springframework" additivity="false">
        <level value="WARN"/>
        <appender-ref ref="Console"/>
    </logger>

    <!--scheduler logger -->
    <logger name="com.andaily.infrastructure.scheduler" additivity="false">
        <level value="DEBUG"/>
        <appender-ref ref="schedulerAppender"/>
    </logger>
    <logger name="com.andaily.service.operation.job" additivity="false">
        <level value="DEBUG"/>
        <appender-ref ref="schedulerAppender"/>
    </logger>


    <root>
        <level value="INFO"/>
        <appender-ref ref="Console"/>
    </root>


</log4j:configuration>  

事实上,XML远比properties灵活。

<param name="Append" value="true"/>  

日志是否作为追加,false则是清空日志文件重写。

Layout就是格式化输出的,时间,log代码所在方法,行数,等等,自己去查吧。

OK。

Related Article