Java日志框架梳理-SLF4J+log4j实践

2,050 阅读7分钟

  log4j的配置文件是用来设置纪录器的级别、存放位置和布局的,可以通过Java属性文件(key=value)格式设置或XML格式设置。log4j配置文件元素简介:

Logger

  Logger是一个允许应用纪录日志的对象,开发者不必考虑输出位置。应用可将具体需要打印的信息通过一个Object传递。Logger是命名了的实体,每个Logger相互独立,它们的名字大小写敏感且遵循层次化命名规则:

如果logger的名称带上一个点号后是另外一个logger的名称的前缀,则前者被称为后者的祖先。如果logger与其后代logger之间没有其他祖先,则前者就被称为子logger之父。

  根logger(rootLogger)位于logger等级的最顶端,它是每个层次等级的共同始祖。获取根logger的方式:

Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

  logger可被分配级别,如果logger没有被分配级别,那它将从没有分配级别的最近祖先继承级别,直至根logger,默认情况下,根logger级别为DEBUG。

  logger可通过additivity标识设置其Appender的叠加性,定义如下:

logger A记录语句的输出会发送给A及其祖先的全部Appender,如果logger A的某个祖先B设置叠加性标识为false,则A的输出会发送给A与B(包含B)之间的所有Appender,但不会发送给B的任何祖先Appender

Appender

  每个Appender可独立配置纪录日志的设备,可以是:控制台、文件、数据库、消息系统等。log4j提供的Appender具体有如下几种:

类型 描述
org.apache.log4j.ConsoleAppender 控制台
org.apache.log4j.FileAppender 文件
org.apache.log4j.DailyRollingFileAppender 每天产生一个日志文件
org.apache.log4j.RollingFileAppender 文件大小到达指定尺寸的时候产生一个新的文件
org.apache.log4j.WriterAppender 将日志信息以流格式发送到任意指定的地方

Layout

  Layout也被称为Formatters,负责对日志时间中的数据进行转换和格式化,Layout决定了数据在一条日志记录中的最终形式。log4j提供的Layout有如下几种:

类型 描述
org.apache.log4j.HTMLLayout 以HTML表格形式布局
org.apache.log4j.PatternLayout 可以灵活地指定布局模式
org.apache.log4j.SimpleLayout 包含日志信息的级别和信息字符串
org.apache.log4j.TTCCLayout 包含日志产生的时间、线程、类别等等信息



  log4j采用类似C语言中printf的打印格式化日志信息,打印参数如下

类型 描述
%m 输出代码中制定的消息
%p 输出日志级别
%r 输出自应用启动到出处该日志记录耗费的毫秒数
%c 输出触发该日志事件的类
%t 输出触发该日志事件的线程
%d 输出日志事件发生的时间,如:%-d{yyyy-MM-dd HH:mm:ss}
%l 输出日志发生的位置,包括类信息、线程、行数

Level

每个打印日志都可以单独指定日志级别,通过配置文件来控制输出级别。log4j提供的日志级别如下:

类型 描述
ALL 最低级别,用于打开所有日志记录
TRACE 指定粒度比DEBUG更细的事件
DEBUG 指定细粒度信息事件,对调试应用程序有帮助
INFO 指定粗粒度信息事件,突出强调程序运行过程
WARN 指定具有潜在危害的情况
ERROR 指定错误事件,程序仍然允许运行
FATAL 指定非常严重的错误事件,可能导致应用程序终止
OFF 最高等级,用于关闭日志记录

SLF4J+log4j实践

  log4j适配器绑定可添加如下pom依赖,添加配置后会自动拉下来两个依赖包,分别是slf4j-api-1.7.25和log4j-1.2.17。

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.25</version>
</dependency>

  log4j必须指定配置文件或默认配置。如果程序中引入了以上包,在没有编写配置文件,且没有设置默认配置器时打印日志,log4j会报如下错误:   

public class Test {

    public static void main(String [] args) {
        //BasicConfigurator.configure();
        Logger logger  = LoggerFactory.getLogger(Test.class);
        logger.debug( " this is {} debug log", Test.class.getName() );
        logger.error( " this is {} error log", Test.class.getName());
    }
}

结果:
log4j:WARN No appenders could be found for logger (com.xiaofan.test.Test).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

  通过BasicConfigurator.configure() 可指定log4j默认配置器,该配置默认生成rootLogger,并添加一个控制台Appender,源码如下:

static public void configure() {
    Logger root = Logger.getRootLogger();
    root.addAppender(new ConsoleAppender(
           new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
  }

  打印日志结果如下:

0 [main] DEBUG com.xiaofan.test.Test  -  this is com.xiaofan.test.Test debug log
2 [main] ERROR com.xiaofan.test.Test  -  this is com.xiaofan.test.Test error log

  编写log4j配置文件有两种方式:Java属性文件(key=value)和XML形式。

  • log4j.properties
      
      属性配置文件范例如下:
### set log levels ###
log4j.rootLogger = debug,stdout,D,E

### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern =  %-d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n

### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 保存异常信息到单独文件 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n


### logger ### 
# 设置后com.xiaofan路径下的日志将只输出ERROR日志
#log4j.logger.com.xiaofan=ERROR

  将log4j.properties文件放到工程的resources文件夹下,如果程序没有显示指定其他配置文件,log4j会默认加载log4j.properties文件作为配置文件。可通过PropertyConfigurator.configure()显示指定外部配置文件。   

  测试代码如下:

package com.xiaofan.test;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by Jerry on 17/7/24.
 */
public class Test {

    public static void main(String [] args) {
        PropertyConfigurator.configure(Test.class.getResource("/log4j.properties"));
        Logger logger  = LoggerFactory.getLogger(Test.class);
        logger.debug( " this is {} debug log", Test.class.getName() );
        logger.error( " this is {} error log", Test.class.getName());
    }
}

结果:
console:
    2017-07-27 09:44:50 DEBUG [com.xiaofan.test.Test]  this is com.xiaofan.test.Test debug log
    2017-07-27 09:44:50 ERROR [com.xiaofan.test.Test]  this is com.xiaofan.test.Test error log
/logs/error.log:
    2017-07-27 09:48:27  [ main:1 ] - [ ERROR ]   this is com.xiaofan.test.Test error log
/logs/log.log:
    2017-07-27 09:48:27  [ main:0 ] - [ DEBUG ]   this is com.xiaofan.test.Test debug log
    2017-07-27 09:48:27  [ main:1 ] - [ ERROR ]   this is com.xiaofan.test.Test error log
  • log4j.xml

      XML配置文件如下:

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

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

    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="[%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p] %c{2\} [%t] - %m%n" />
        </layout>
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="levelMin" value="debug" />
            <param name="levelMax" value="error" />
            <param name="AcceptOnMatch" value="true" />
        </filter>
    </appender>

    <appender name="ERROR" class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="logs/error.log" />
        <param name="Append" value="true" />
        <param name="threshold" value="error" />
        <param name="MaxBackupIndex" value="10" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
        </layout>
    </appender>

    <appender name="INFO" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="logs/log.log" />
        <param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="[%d{MMdd HH:mm:ss SSS\} %-5p] [%t] %c{3\} - %m%n" />
        </layout>
    </appender>

    <logger name="mylogger" additivity="true">
        <level value="debug" />
        <appender-ref ref="INFO" />
    </logger>

    <root>
        <priority value ="debug"/>
        <appender-ref ref="INFO"/>
        <appender-ref ref="ERROR" />
        <appender-ref ref="console" />
    </root>

</log4j:configuration>

 将log4j.xml文件放到工程的resources文件夹下,如果程序没有显示指定其他配置文件,log4j会默认加载log4j.xml文件作为配置文件。可通过DOMConfigurator.configure()显示制定外部配置文件。
 
  测试代码如下:

public class Test {

    public static void main(String [] args) {
        DOMConfigurator.configure(Test.class.getResource("/log4j.xml"));
        Logger logger  = LoggerFactory.getLogger(Test.class);
        logger.debug( " this is {} debug log", Test.class.getName() );
        logger.error( " this is {} error log", Test.class.getName());
    }
}

结果:
控制台:
    [2017-07-27 12:43:20,474 DEBUG] test.Test [main] -  this is com.xiaofan.test.Test debug log
    [2017-07-27 12:43:20,484 ERROR] test.Test [main] -  this is com.xiaofan.test.Test error log
/logs/error.log
    ERROR (com.xiaofan.test.Test:18)-  this is com.xiaofan.test.Test error log
/logs/log.log
    [0727 12:50:04 829 DEBUG] [main] xiaofan.test.Test -  this is com.xiaofan.test.Test debug log
    [0727 12:50:04 830 ERROR] [main] xiaofan.test.Test -  this is com.xiaofan.test.Test error log