上一篇:spring boot 1.5.4 定时任务和异步调用(十)

 

Spring Boot整合log4j2

spring boot整合log4j2项目spring-boot-jsp源码:

spring-boot相关项目源码,

码云地址:https://git.oschina.net/wyait/springboot1.5.4.git

github地址https://github.com/wyait/spring-boot-1.5.4.git


1.1  log4j2概要

对于我们开发人员来说,日志记录往往不被重视。在生产环境中,日志是查找问题来源的重要依据。日志可记录程序运行时产生的错误信息、状态信息、调试信息和执行时间信息等多种多样的信息。可以在程序运行出现错误时,快速地定位潜在的问题源。

 

目前常用的日志框架有java.util.loggingcommons loggingslf4jlog4j1.xlogbacklog4j2.x 等若干种,这里我们使用log4j2框架进行日志管理,先介绍下日志框架的发展史以及优点。

1.1.1     java日志框架发展史

 

  • 1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java

日志软件包,即log4j。后来log4j成为Apache基金会项目中的一员。

期间log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议Sun引入log4j到java的标准库中,但Sun拒绝了。

 

  • 2002年Java1.4发布,Sun推出了自己的日志库jul(java util logging),其实现基本模仿了log4j的实现。在JUL出来以前,log4j就已经成为

一项成熟的技术,使得log4j在选择上占据了一定的优势。

接着,Apache推出了jakarta commons logging,jcl只是定义了一套日志接口(其内部也提供一个simple log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你的应用代码里,只需调用commons logging的接口,底层实现可以是log4j,也可以是java util logging。

 

  • 后来(2006年),Ceki Gülcü(Gulcu)不适应Apache的工作方式,离开了Apache。然后先后创建了slf4j(日志门面接口,类似于commons logging)

和logback(slf4j的实现)两个项目,并回瑞典创建了QOS公司,QOS官网上是这样描述logback的:The Generic,Reliable Fast&FlexibleLogging Framework(一个通用,可靠,快速且灵活的日志框架)。

 

  • 现今,Java日志领域被划分为两大阵营:commons logging阵营和slf4j阵营。 commons logging在Apache大树的笼罩下,有很大的用户基数。

但有证据表明,形式正在发生变化。2013年底有人分析了GitHub上30000个项目,统计出了最流行的100个Libraries,可以看出slf4j的发展

趋势更好。如下图所示:

wKioL1nNohGDPUoEAAEuljEPugo210.png

 

Apache眼看有被logback反超的势头,于2012年7月重写了log4j 1.x,成立了新的项目log4j2.x。log4j2在各个方面都与logback非常相似。

 

1.1.2     常用日志框架介绍

这些日志系统有什么区别,开发时如何选择适合自己项目的日志系统呢?日志系统可分为两类。

 

一类:只提供接口不提供实现,如 Apache Commons Logging 和 slf4j。这类日志系统需要和具体的日志系统一起使用,优点是可以自由切换不同的日志实现系统。如果你的项目以后要打成 jar 包被别的系统使用或者你以后可能更换日志系统,通常使用这一类日志系统。

 

另一类:是具体的日志系统实现。如 log4j1.x、logback、log4j2.x、java.util.logging等。

 

下图清晰的展示了 slf4j 和其它日志系统的关系:

wKiom1nNolzRdtxCAAFmo8zIkco476.png

 

slf4j(SimpleLogging Facade for Java),面向 java 的简单日志门面,人如其名,slf4j 是其他日志的门面,它提供统一的接口,并不提供实现,不是具体的日志系统。

 

log4j1 曾经被广泛使用,2015年8月已停止更新,logback和log4j2作为它的替代者,拥有更好的性能,有很多的改进,下面重点讲一下 logback 和 log4j2 的特性。

 

1.1.3  logback相比 log4j1 的优点

 

1、 性能的提升。Logback 的内核重写了,在某些特定的场景上性能提升 10 倍以上,同时所需的内存更加少。

2、 非常充分的测试。Logback经过了几年,数不清小时的测试,与log4j1的测试相比不在同一个级别,因此 logback 更稳定可靠。

3、 非常自然的实现了slf4j。而log4j1 和 slf4j 一起使用需要适配层。

4、 自动重新加载配置文件。当配置文件修改了,Logback-classic能自动重新加载配置文件,不需要重启服务器。

5、 优雅地从I/O错误中恢复。如果一个文件服务器临时宕机,你不需要重启应用,日志功能就能正常工作。

6、 配置文件可适应多环境。通常在开发、测试、生产环境,需要变换日志的配置文件。而在不同环境下,配置文件只有一些很小的不同,为了避免重复,logback支持使用,和进行条件处理,同一个配置文件就可以在不同的环境中使用了。

7、 过滤器。生产环境中,有时需要低级别的日志来查明问题,在log4j1 中,只有降低日志级别,这样的话会打出大量的日志而影响性能。而logback 中,你可以继续保持那个日志级别而除掉某种特殊情况。

8、 自动压缩归档日志文件。压缩通常是异步执行的,所以即使是很大的日志文件,你的应用都不会因此而被阻塞。

9、 通过配置自动去除旧的日志文件。

 

1.1.4     log4j2 的优点

log4j2在各个方面都与logback非常相似,那么为什么我们还需要log4j 2呢?

 

1、  可配置的审计型日志。log4j1和logback在重新配置的时候会丢失之前的日志文件,log4j2不会。log4j2自身内部报的exception会被发现,但是log4j1和logback不会。

 

2、  下一代异步logger。log4j 2是基于LMAXDisruptor库的(一个用于在线程间通信的高效低延迟且简单的框架),在多线程场景下,它的日志吞吐量比其他框架多出10倍以上。

 

3、  可运行在免垃圾收集模式。这样可以减少垃圾收集器的压力和提供更好的响应时间性能。

 

4、  插件式结构。可根据自己的需要扩展框架,可以实现自己的logger、appenders、filters、layouts、lookups 和patternconverters,而无需对log4j2做任何更改。

 

5、 Java 5的并发性。log4j2利用Java 5中的并发特性支持,尽可能地执行最低层次的加锁,log4j1中存留的死锁问题,很多已经在logback中解决,但logback的很多类仍然保持着较高层次的同步。如果你的程序仍然饱受内存泄漏的折磨,请毫不犹豫地试一下log4j2。

 

下图为Apache Logging PMC成员Christian Grobmeier 在2013年7月发表的一篇标题为《Log4j2:性能几近于疯狂》的文章;

wKioL1nNoiayjRTlAACxJeuHaVE278.png

1.2    spring boot集成log4j2

使用spring-boot-jsp项目,项目源码:spring-boot-jsp

  • 导入依赖

<!-- 导入log4j2依赖 -->

      <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-log4j2</artifactId>

      </dependency>

      <!-- log4j2支持异步日志,导入disruptor依赖 -->

      <dependency>

        <groupId>com.lmax</groupId>

        <artifactId>disruptor</artifactId>

        <version>3.3.6</version>

      </dependency>

  • 配置文件:在项目目录/resources资源文件根目录下创建 log4j2.xml 文件,详细配置如下:

 

<?xmlversion="1.0" encoding="UTF-8"?>

<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE >ALL -->

<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出;可以设置成OFF(关闭)Error(只输出错误信息)-->

<!--monitorIntervalLog4j2能够自动检测修改配置文件和重新配置本身,设置间隔秒数-->

<Configurationstatus="WARN" monitorInterval="30">

   <Properties>

   <!-- 缺省配置(用于开发环境),配置日志文件输出目录和动态参数。其他环境需要在VM参数中指定;

      sys:”表示:如果VM参数中没指定这个变量值,则使用本文件中定义的缺省全局变量值 -->

      <Propertyname="instance">spring-boot-log</Property>

      <Propertyname="log.dir">D:\log\logs</Property>

   </Properties>

   <!-- 定义所有的appender -->

   <Appenders>

      <!--这个输出控制台的配置-->

      <Console name="Console"target="SYSTEM_OUT">

        <!--输出日志的格式-->

        <PatternLayout

           pattern="[%date{yyyy-MM-ddHH:mm:ss.SSS}][%thread][%level][%class][%line]:%message%n" />

      </Console>

      <!-- info及以上级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->

      <RollingRandomAccessFilename="infoLog"

        fileName="${log.dir}/${instance}-info.log"

        filePattern="${log.dir}/%d{yyyy-MM}/${instance}-info-%d{yyyy-MM-dd}-%i.log.gz"

        append="true">

        <PatternLayout

           pattern="[%date{yyyy-MM-ddHH:mm:ss.SSS}][%thread][%level][%class][%line]:%message%n" />

        <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch-->

        <Filters>

           <ThresholdFilterlevel="info" onMatch="ACCEPT"

              onMismatch="NEUTRAL"/>

        </Filters>

        <Policies>

           <!-- 基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour -->

           <TimeBasedTriggeringPolicyinterval="1"

              modulate="true" />

           <!-- 基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小 -->

           <SizeBasedTriggeringPolicysize="1MB" />

           <!-- DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性) -->

        </Policies>

      </RollingRandomAccessFile>

  

      <!-- warn级别的日志信息 -->

      <RollingRandomAccessFilename="warnLog"

        fileName="${log.dir}/${instance}-warn.log"

        filePattern="${log.dir}/%d{yyyy-MM}/${instance}-warn-%d{yyyy-MM-dd}-%i.log.gz"

        append="true">

        <Filters>

           <ThresholdFilterlevel="error" onMatch="DENY"

              onMismatch="NEUTRAL"/>

           <ThresholdFilterlevel="warn" onMatch="ACCEPT"

              onMismatch="DENY" />

        </Filters>

         <PatternLayout

           pattern="[%date{yyyy-MM-ddHH:mm:ss.SSS}][%thread][%level][%class][%line]:%message%n" />

        <Policies>

           <TimeBasedTriggeringPolicyinterval="1"

              modulate="true" />

           <SizeBasedTriggeringPolicysize="1MB" />

        </Policies>

      </RollingRandomAccessFile>

     

      <!-- error级别的日志信息 -->

      <RollingRandomAccessFilename="errorLog"

        fileName="${log.dir}/${instance}-error.log"

        filePattern="${log.dir}/%d{yyyy-MM}/${instance}-error-%d{yyyy-MM-dd}-%i.log.gz"

        append="true">

        <Filters>

           <ThresholdFilterlevel="ERROR" onMatch="ACCEPT"

              onMismatch="DENY" />

        </Filters>

        <PatternLayout

           pattern="[%date{yyyy-MM-ddHH:mm:ss.SSS}][%thread][%level][%class][%line]:%message%n" />

        <Policies>

           <TimeBasedTriggeringPolicyinterval="1"

              modulate="true" />

           <SizeBasedTriggeringPolicysize="1MB" />

        </Policies>

      </RollingRandomAccessFile>

   </Appenders>

  

   <!-- 全局配置,默认所有的Logger都继承此配置 -->

   <!-- 用来配置LoggerConfig,包含一个root logger和若干个普通logger

   additivity指定是否同时输出log到父类的appender,缺省为true

   一个Logger可以绑定多个不同的Appender。只有定义了logger并引入的appenderappender才会生效。 -->

   <Loggers> <!-- 第三方的软件日志级别 -->

      <loggername="org.springframework" level="info"additivity="true">

        <AppenderRef ref="warnLog"/>

        <AppenderRef ref="errorLog"/>

      </logger>

      <loggername="java.sql.PreparedStatement" level="debug"

        additivity="true">

        <AppenderRef ref="Console"/>

      </logger>

      <!-- root logger 配置 -->

      <Root level="info"includeLocation="true">

        <AppenderRef ref="infoLog"/>

        <AppenderRef ref="Console"/>

        <AppenderRef ref="errorLog"/>

      </Root>

      <!-- AsyncRoot - 异步记录日志 - 需要LMAXDisruptor的支持 -->

      <!-- <AsyncRootlevel="info" additivity="false">

        <AppenderRef ref="Console"/>

        <AppenderRef ref="infoLog"/>

        <AppenderRef ref="errorLog"/>

      </AsyncRoot> -->

   </Loggers>

</Configuration>

 

用于测试,所以SizeBasedTriggeringPolicy日志文件大小最大设置为1MB;实际使用根据情况调整;

 

Controller类:

   @RequestMapping("/wyait")

   @ResponseBody

   public String getMsg(HttpServletResponseresponse) {

      LOGGER.debug("===========debug信息>>>>"+ paramProperties);

      LOGGER.info("===========info信息>>>>"+ paramProperties);

      LOGGER.trace("I am trace log.");

      LOGGER.debug("I am debug log.");

      LOGGER.warn("I am warn log.");

      LOGGER.error("I am error log.");

      // 手动异常

      System.out.println(1 / 0);

      // 会有中文乱码问题 TODO

      return paramProperties.getWyaitName() +" 正在写"

           + paramProperties.getWyaitTitle() +"!总结:"

           + paramProperties.getWyaitMessage();

   }

 

启动项目,访问:http://127.0.0.1:8080/cat/wyait

wKiom1nNonfwQiEfAAArEdlm5co581.png

 

查看日志目录:

wKiom1nNon_AinPFAAAegQpysMM118.png

1.1    log4j2配置属性详解

(1)根节点Configuration有两个属性:statusmonitorinterval,有两个子节点:AppendersLoggers(表明可以定义多个AppenderLogger).

 

    status用来指定log4j本身的打印日志的级别.

    monitorinterval用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s.(如果更改配置文件,不用重启系统)

 

(2)Appenders节点,常见的有三种子节点:ConsoleRollingFileFile.

 

    Console节点用来定义输出到控制台的Appender.

        name:指定Appender的名字.

        target:SYSTEM_OUT SYSTEM_ERR,一般只设置默认:SYSTEM_OUT.

        PatternLayout:输出格式,不设置默认为:%m%n.

 

    File节点用来定义输出到指定位置的文件的Appender.

        name:指定Appender的名字.

        fileName:指定输出日志的目的文件带全路径的文件名.

        PatternLayout:输出格式,不设置默认为:%m%n.

 

    RollingFile节点用来定义超过指定大小自动删除旧的创建新的的Appender.

        name:指定Appender的名字.

        fileName:指定输出日志的目的文件带全路径的文件名.

        PatternLayout:输出格式,不设置默认为:%m%n.

        filePattern:指定新建日志文件的名称格式.

        Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志.

        TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hourmodulate=true用来调整时间:比如现在是早上3aminterval4,那么第一次滚动是在4am,接着是8am12am...而不是7am.

        SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小.

        DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)

 

(3)Loggers节点,常见的有两种:RootLogger.

 

    Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出

        level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn <Error < Fatal < OFF.

        AppenderRefRoot的子节点,用来指定该日志输出到哪个Appender.

 

    Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。

        level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn <Error < Fatal < OFF.

        name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点.

        AppenderRefLogger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了,那么会在指定的这个AppenderRootAppender中都会输出,此时我们可以设置Loggeradditivity="false"只在自定义的Appender中进行输出。

 

(4)关于日志level.

 

共有8个级别,按照从低到高为:All< Trace < Debug < Info < Warn < Error < Fatal < OFF.

 

        All:最低等级的,用于打开所有日志记录.

        Trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出.

        Debug:指出细粒度信息事件对调试应用程序是非常有帮助的.

        Info:消息在粗粒度级别上突出强调应用程序的运行过程.

        Warn:输出警告及warn以下级别的日志.

        Error:输出错误信息日志.

        Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志.

        OFF:最高等级的,用于关闭所有日志记录.

 

程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。

 

 

 

spring-boot相关项目源码,

码云地址:https://git.oschina.net/wyait/springboot1.5.4.git

github地址https://github.com/wyait/spring-boot-1.5.4.git


spring boot系列文章:

spring boot 1.5.4 概述(一)

spring boot 1.5.4 入门和原理(二)

spring boot 1.5.4 之web开发(三)

spring boot 1.5.4 整合JSP(四)

spring boot 1.5.4 集成devTools(五)

spring boot 1.5.4 集成JdbcTemplate(六)

spring boot 1.5.4 集成spring-Data-JPA(七)

spring boot 1.5.4 配置文件详解(八)

spring boot 1.5.4 统一异常处理(九)

spring boot 1.5.4 定时任务和异步调用(十)

spring boot 1.5.4 整合log4j2(十一)

spring boot 1.5.4 整合 mybatis(十二)

spring boot 1.5.4 整合 druid(十三)

spring boot 1.5.4 之监控Actuator(十四)

spring boot 1.5.4 整合webService(十五)

spring boot 1.5.4 整合redis、拦截器、过滤器、监听器、静态资源配置(十六)

spring boot 1.5.4 整合rabbitMQ(十七)

spring boot 1.5.4 集成Swagger2构建Restful API(十八)

spring boot 1.5.9 整合redis(十九