日志那些事之三——日志配置文件解析以及log4j2整合到spring-boot

1 Spring-boot配置文件的使用

  由于日志服务一般都在ApplicationContext创建前就初始化了,它并不是必须通过Spring的配置文件控制。因此通过系统属性和传统的Spring Boot外部配置文件依然可以很好的支持日志控制和管理。
根据不同的日志系统,你可以按如下规则组织配置文件名,就能被正确加载:

Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
Log4j2:log4j2-spring.xml, log4j2.xml
JDK (Java Util Logging):logging.properties

  Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置(如使用logback-spring.xml,而不是logback.xml)。
众智平台log4j2的配置:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
            <Appenders>
                        <Console name="Console" target="SYSTEM_OUT">
                                    <PatternLayout pattern="%m%n" />
                        </Console>
            </Appenders>
            <Loggers>
                        <Root level="INFO">
                                     <AppenderRef ref="Console" />
                         </Root>
             </Loggers>
 </Configuration>

2 Log4j2日志配置文件解析与使用

  下面以实际项目中日志为例,从简单到复杂,讲解log4j2日志框架配置文件的使用。

2.1 简单版日志配置,输出控制台

  配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%-5p] %d %c - %m%n"/>
        </Console>
    </Appenders>
    <Loggers>
         <Root level="debug">
            <AppenderRef ref="Console"/>
          </Root>
    </Loggers>
</Configuration>

  具体日志如下,只在控制台输出:
这里写图片描述
  将上述配置的root的level改为info后
这里写图片描述
  将上述配置的root的level改为error后
这里写图片描述

2.2 简单版日志配置,控制台、文件双输出

  配置文件如下

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%-5p] %d %c - %m%n"/>
        </Console>
        <File name="File" fileName="dist/my.log">
            <PatternLayout pattern="[%-5p] %d %c - %m%n"/>
        </File>
    </Appenders>
    <Loggers>
         <Root level="error">
            <AppenderRef ref="Console"/>
         </Root>
    </Loggers>
</Configuration>

  控制台输出:
这里写图片描述
  文件输出如下:
这里写图片描述
   注意,这个时候虽然生成了对应的文件,但是并没有日志输出到这个文件。修改配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%-5p] %d %c - %m%n"/>
        </Console>
        <File name="File" fileName="dist/my.log">
            <PatternLayout pattern="[%-5p] %d %c - %m%n"/>
        </File>
    </Appenders>
    <Loggers>
<Logger name="com.onlyisssilence.muya" level="INFO">
             <AppenderRef ref="File"/>
        </Logger>
         <Root level="error">
             <AppenderRef ref="Console"/>
         </Root>
    </Loggers>
</Configuration>

 控制台和文件分别输出如下:
这里写图片描述
这里写图片描述
  这个时候日志文件上面已经有日志输出了。

2.3 日志的级别“透传”——additivity属性

注意一个问题:对比配置文件修改前后的控制台的输出可以看到,配置修改前控制台的输出日志级别为error,意味着只有erro级别以上的日志才会打印,事实也确实是如此,如配置:

<Root level="error">
         <AppenderRef ref="Console"/>
    </Root>

  修改了配置文件后,多加了一个logger,root的level并没有变化,但是这个时候的控制台输出日志级别变大了,info以上的级别都打印出来了,再继续做实验,修改logger的日志级别为error,看到控制台和文件输出如下:
这里写图片描述
  可以看到控制台和日志文件的日志输出级别均为error,得出结论:
  有了logger之后,日志级别是由logger的级别控制?
  (只要某个logger接受了该log请求,那么作为父亲的Root就会跟着接受此log请求,而不再考虑它的level )要想让root和logger的级别互不干扰,准确的说是不让logger控制root的日志输出级别,可以在logger中使用addtivity属性,配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[%-5p] %d %c - %m%n"/>
        </Console>
        <File name="File" fileName="dist/my.log">
            <PatternLayout pattern="[%-5p] %d %c - %m%n"/>
        </File>
    </Appenders>
    <Loggers>
        <Logger name="com.onlyisssilence.muya" level="warn" additivity = "false">
            <AppenderRef ref="File"/>
        </Logger>
        <Root level="info">
            <AppenderRef ref="Console"/>
            <!--<AppenderRef ref="taoge"/>-->
        </Root>
    </Loggers>
</Configuration>

  控制台和文件输出如下:
这里写图片描述
  如上,发现一个问题:日志文件中这个时候确实打印的是warn以上级别的日志,控制台也确实是info级别以上的日志,但是,日志文件只打印与业务相关的日志,控制台这个时候打印的是与业务无关的系统和数据库操作日志,这是为什么?
  Logger的appender根据参数additivity决定是否要叠加root的appender,logger的级别是其自身定义的级别,和root的级别没什么关系。判断一个类的日志输出情况,首先找到这个类所在的logger(没有特别定义则默认为root),然后根据以上规则判断出这个logger的appender和level。然后既可以知道这个类的哪些日志会被输出到哪些地方了。注意:任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 因此对于上述现象的解释是:业务相关的类都在包com.onlyisssilence.muya下,它们的日志输出到了文件中,而数据库以及其他的框架类日志使用的是默认的logger——root,而root的appender为控制台,所以均会打印到控制台上。
  在上述的logger配置中,如下:

<Logger name="com.onlyisssilence.muya" level="warn" additivity = "false">
       <AppenderRef ref="File"/>
</Logger>
<Root level="info">
       <AppenderRef ref="Console"/>
</Root>

  可以看到子logger的appender只有file,其属性”name”为”com.onlyisssilence.muya”,这意味着在”com.onlyisssilence.muya”包下所有的类打印出来的业务日志的appender只有一个”File”,并输出到该appender指定的文件中,如上图所示,这些包下的类唯一对应着这一个logger,并不会再在其他logger下(这里指的是父logger——root);父root的appender只有console,这个时候”com.onlyisssilence.muya”中的类由于已经从属于了子logger了,他们的业务日志就不会打印到root这个logger所在appender上(也就是控制台)。
如下修改配置文件
这里写图片描述
  日志打印如下:
这里写图片描述

2.4 Logger配置中root和logger的区别

  上面出现的现象实际上是logger配置元之前的关系,是一个“父子”级的概念。Logger配置元分为“根logger”——root和普通自定义的logger。Root默认输出所有。而新添加的logger根据其属性name所指示的包路径,负责把包下的类打印的日志输出到指定文件。这个特性有利于在比较大的项目中对日志进行分类。
Logger的等级制度
  Root Logger位于Logger最高层级,也就是说,它是所有Logger的祖先。它有2个特别的地方
   它总是存在;
   不能用name来获取它;
  调用类的静态方法Logger.getRootLogger可以获取Root Logger。所有其他的Loggers都是调用类的静态方法Logger.getLogger来实例化的。Logger.getLogger需要传入要创建的Logger 的name作为参数。Logger类的一些基本的方法如下:
这里写图片描述
  当有多个logger的时候,不同类中的日志到底是按照哪一个logger的appender来输出日志呢?[看源码]
看下图的日志配置文件:
这里写图片描述
这里写图片描述
  上述的appender有4个,一个控制台appender——console,三个文件appender——File1、File2、File3,有6个logger,可以看到这6个logger的关系如下:
这里写图片描述
  打印的控制台和文件日志如下:
这里写图片描述
这里写图片描述
这里写图片描述
  现象:
+ File appender中的每个日志文件都生成了,my1.log/my2.log/my3.log;
+ my2.log、my3.log日志文件分别对应着com.onlyisssilence.muya.SchedledCon下的ScheduleRefreshDatabase、ScheduleTask类中打印的日志,my1.log日志文件中并没有任何的日志文件输出;
+ 控制台输出了系统日志以及Log4j2Test2类中的业务日志,其中系统日志使用的默认的root这个logger,Log4j2Test2类的业务日志使用的是com.onlyisssilence.muya.log4j2Test这个logger;
分析结论:
  logger存在父子级别的概念,其中root是根级别的,当待打印的文件没有设置任何所属的logger时,会默认使用root级别的,如上例中的sql的日志、系统日志(它们均没有设置其logger),对于这种层级的包中的类,如果重复设置了其logger那么以离该文件最近的节点设置的logger为主。

2.5 Log4j2中特殊appender之JAP

  项目中有的时候需要存储一些操作日志,比如用户登录登出,查询信息,删除信息等,这些操作对于前端可能就是一个接口的调用,对于后端而言就是controller层中的一个方法的调用,这种业务场景的需求可以考虑使用log4j2+切面技术的相结合来实现,总的思路是,每个接口添加日志操作的自定义注解;注解的处理类中调用log4j2的日志工具打印日志;打印的日志使用JAP这种属性的appender,这种appender再通过定义日志操作类实现自动的入库。

展开阅读全文

没有更多推荐了,返回首页