spring boot 1.5.4 整合log4j2(十一)

  1. 云栖社区>
  2. 博客>
  3. 正文

spring boot 1.5.4 整合log4j2(十一)

技术小阿哥 2017-11-27 17:10:00 浏览878
展开阅读全文

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:最高等级的,用于关闭所有日志记录.

 

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



本文转自 wyait 51CTO博客,原文链接:http://blog.51cto.com/wyait/1969613,如需转载请自行联系原作者

网友评论

登录后评论
0/500
评论
技术小阿哥
+ 关注