日志


一、logback、log4j、slf4j

  • slf4j(Simple logging Facade for Java) 简单日志门面,日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,没有任何日志实现,只有一个jar包(slf4j-api.jar)。

  • log4jlogback是具体的日志框架。这两个日志框是同一个作者开发,后者性能更高。 logbak直接实现slf4j接口,性能更高。springboot默认日志框架为logback

img

二、logback

logback是由log4j创始人设计的另一个开源日志组件。

官方网站: http://logback.qos.ch

1、logback 模块

  • logback-core:其它两个模块的基础模块
  • logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging
  • logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能

2、日志级别

共有:trace、debug、info、warn、error 5个级别。

排序为: TRACE < DEBUG < INFO < WARN < ERROR。

如果设置为WARN,则低于WARN的信息都不会输出

3、springboot加载步骤

(1)LogBack在类路径下优先查找 logback.groovy 的文件。如果 logback.groovy 没有找到,则继续查找 logback-test.xml 文件。

(2)若 logback-test.xml 文件没有找到,则会类路径下查找 logback.xmllogback-spring.xml 文件。

(3) 如果没有任何配置文件,LogBack 使用 BasicConfigurator 启动默认配置,配置会将日志输出控制台上不会写进日志文件,它提供了默认的最基础的日志功能。

如果配置文件 logback-test.xmllogback.xml 都不存在,那么 logback 默认地会调用BasicConfigurator ,创建一个最小化配置。最小化配置由一个关联到根 loggerConsoleAppender 组成。输出用模式为 %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%nPatternLayoutEncoder 进行格式化。root logger 默认级别是 DEBUG

logback-spring.xml

logback-spring.xml 只有在Spring应用程序运行的时候才生效,即带有@SpringBootApplication注解的类启动的时候才会生效。logback-spring.xml 使用方法基本和 logback.xml 等同,但是2者的加载顺序是不一样的。

logback.xml—>application.properties—>logback-spring.xml

logback.xml 加载早于 application.properties ,所以如果你在 logback.xml 使用了变量时,而恰好这个变量是写在 application.properties 时,那么就会获取不到,只要改成 logback-spring.xml 就可以解决。

使用方式

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTest {

  private static Logger logger = LoggerFactory.getLogger(MyTest.class);

  @Test
  public void test() {
    logger.info("日志");
  }
}

4、常用配置如下

(1)根节点 <configuration>

根节点 <configuration>,包含下面三个属性:

  • scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。

  • scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。

  • debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。

<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!--其他配置省略-->
</configuration> 

(2)<contextName>上下文名称

<configuration> 的子节点 <contextName>:用来设置上下文名称,每个logger都关联到logger上下文,默认上下文名称为default。但可以使用 <contextName> 设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。

<configuration scan="true" scanPeriod="60 seconds" debug="false">
     <contextName>myAppName</contextName>
    <!--其他配置省略-->
</configuration> 

(3)<property> 定义变量

<configuration> 的子节点 <property> :用来定义变量值,它有两个属性name和value,通过<property> 定义的值会被插入到 logger上下文中,可以使“${}”来使用变量。

  • name: 变量的名称

  • value: 变量定义的值

<configuration scan="true" scanPeriod="60 seconds" debug="false">
   <property name="APP_Name" value="myAppName" />
   <contextName>${APP_Name}</contextName>
   <!--其他配置省略-->
</configuration>

(4)<timestamp>获取时间戳

<configuration> 子节点 <timestamp>:获取时间戳字符串,他有两个属性key和datePattern

  • key: 标识此 <timestamp> 的名字;

  • datePattern: 设置将当前时间(解析配置文件的时间)转换为字符串的模式,遵循java.txt.SimpleDateFormat的格式。

<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
    <contextName>${bySecond}</contextName>
    <!-- 其他配置省略-->
</configuration>

(5)<conversionRule> 自定义字符

自定义字符类,继承自 ClassicConverter,重写 convert ,返回值即为自定字符串

public class MySampleConverter extends ClassicConverter {
  long start = System.nanoTime();
  @Override
  public String convert(ILoggingEvent event) {
    long nowInNanos = System.nanoTime();
    return Long.toString(nowInNanos-start);
  }
}

<conversionRule> 标签中定义自定义字符串

  • 属性 conversionWord:变量名,后续引用时使用
  • 属性 converterClass:上面的自定义字符的类
<configuration>

  <conversionRule conversionWord="nanos" 
                  converterClass="chapters.layouts.MySampleConverter" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%-6nanos [%thread] - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>
  • 当需要在日志记录中添加自定义文本时,仅支持在<pattern>中添加ip或其他自定义的字段,不支持在目录或文件名<fileNamePattern>中使用。

  • 如果想在文件目录或文件名中添加自定义字段,可以引入springboot中的参数<springProperty scope="context" name="LOG_HOME" source="logPath"/>

  • 如果需要使用springboot配置中不存在的参数,可以在logback-spring.xml中加入<define>

<define name="initIp" class="com.test.util.InitIpUtil"/>
<springProperty scope="context" name="port" source="server.port" />

...
<fileNamePattern>
    /data/logs/java-${initIp}-${port}
</fileNamePattern>
@Component
public class InitIpUtil extends PropertyDefinerBase {
    @Override
    public String getPropertyValue() {
        return initIpAndPort();
    }
    public static String initIpAndPort() {
        String subIp = null;
        try{
            InetAddress addr = InetAddress.getLocalHost();
            String ip = addr.getHostAddress();
            subIp = ip.substring(ip.lastIndexOf(".",ip.lastIndexOf(".")-1)+1);
        }catch (Exception e){
            e.printStackTrace();
        }
        return subIp;
    }
}

(6)<appender>写日志的组件

<configuration>子节点<appender>:负责写日志的组件,它有两个必要属性name和class。

  • name:指定appender名称,
  • class:指定appender的全限定名

Logback会把书写日志事件的任务委托给叫做appender的组件,appenders必须实现ch.qos.logback.core.Appender接口,该接口方法如下:

package ch.qos.logback.core;

import ch.qos.logback.core.spi.ContextAware;
import ch.qos.logback.core.spi.FilterAttachable;
import ch.qos.logback.core.spi.LifeCycle;

public interface Appender<E> extends LifeCycle, ContextAware, FilterAttachable {

  public String getName();
  public void setName(String name);
  void doAppend(E event);

}

(6-1) Appender分类

1、ConsoleAppender

日志信息输出到控制台,也就是通过 System.out 或者 System.err 输出,前者是默认值。

子标签 类型 备注
encoder Encoder 编码器。
target String 有效值为System.out或者System.err,默认为System.out。
withJansi boolean 默认为false,设为true激活Jansi库,该库提供了windows机器上ANSI颜色编码支持,用不上。
<configuration>
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <!-- 格式化输出:
                %date(d%)表示日期,
                %thread表示线程名,
                %-5level:级别从左显示5个字符宽度,
                   %logger{36}表示logger名字最长36个字符,否则按照句点分割,
                %msg:日志消息,
                %n是换行符 -->
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} - %msg%n</Pattern>
            </layout>
        </encoder>
   </appender>

   <root level="DEBUG">
      <appender-ref ref="STDOUT" />
   </root>
</configuration>
2、FileAppender

OutputStreamAppender的子类,输出日志信息到文件中,目标文件通过File选项指定。

子标签 类型 备注
append boolean 是否追加到指定文件。
encoder Encoder 编码器。
file String 写入日志信息的文件名,如果文件不存在,自动创建。
prudent boolean 谨慎模式写入,默认为false。如果为 true,当多个JVM中的Appender实例写入相同文件时,谨慎模式下会串行I/O操作,效率低。
<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>testFile.log</file>
        <append>true</append>
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="FILE" />
    </root>
</configuration>

上述配置表示把>=DEBUG级别的日志都输出到testFile.log

日志文件唯一命名(通过timestamp)案例如下

<timestamp>元素两个必选属性为key和datePattern,可选属性为timeReference,key指定名字,dataPattern指定日期转换格式,timeReference指定引用的时间戳。

<configuration>

  <!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
       the key "bySecond" into the logger context. This value will be
       available to all subsequent configuration elements. -->
  <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss" timeReference="contextBirth"/>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <!-- use the previously created timestamp to create a uniquely
         named log file -->
    <file>log-${bySecond}.txt</file>
    <encoder>
      <pattern>%logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>
3、RollingFileAppender

滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。例如,写入日志信息到名为log.txt的文件,由于超出指定的文件大小限制,日志输出到另一个文件。

子标签 类型 备注
file String 参考FileAppender。
append boolean 参考FileAppender。
encoder Encoder 编码器。
rollingPolicy RollingPolicy 滚动策略。
triggeringPolicy TriggeringPolicy 触发策略。
prudent boolean 参考FileAppender。
滚动策略

滚动策略负责日志文件移动和重命名相关滚动步骤,该接口api如下:

package ch.qos.logback.core.rolling;  

import ch.qos.logback.core.FileAppender;
import ch.qos.logback.core.spi.LifeCycle;

public interface RollingPolicy extends LifeCycle {

  public void rollover() throws RolloverFailure;
  public String getActiveFileName();
  public CompressionMode getCompressionMode();
  public void setParent(FileAppender appender);
}

滚动策略有以下几种

TimeBasedRollingPolicy(基于时间的滚动策略)
Size and time based rolling policy(基于文件大小和时间的滚动策略)
  • TimeBasedRollingPolicy(基于时间的滚动策略)

基于时间的滚动策略是最长使用的滚动策略,可以通过天或者月份制定何时滚动。

子标签 类型 备注
fileNamePattern String 必选参数,定义了归档日志文件的名字,它的值由文件名和%d的占位转换符组成,如果没有指定时间和日期格式,默认为yyyy-MM-dd。 多个%d转换符/var/log/%d{yyyy/MM, aux}/myapplication.%d{yyyy-MM-dd}.log
maxHistory int 可选参数,表示日志文件保存的最大数量。例如:如果按天滚动,该值设为30,则日志文件最多保存30天。
totalSizeCap int 可选参数,表示所有归档日志文件的的文件大小,和maxHistory结合使用,maxHistory优先于totalSizeCap。
cleanHistoryOnStart boolean 可选参数,表示appender启动时是否清除归档日志文件,默认为false。

下面是一些fileNamePattern的示例:

文件命名格式 滚动计划 备注
/wombat/foo.%d 按日滚动,由于%d后缺失日期和时期格式,采用默认格式yyyy-MM-dd 如果设置file属性(日志文件名),文件格式如下:昨天:/wombat/foo.2019-05-05当天:/wombat/foo.2019-05-06 如果设置file属性为/wombat/foo.txt,文件格式如下 昨天:/wombat/foo.2019-05-05当天:/wombat/foo.txt
/wombat/%d{yyyy/MM}/foo.txt 按月滚动 如果没设置file属性,文件格式如下:上个月:/wombat/2019/05/foo.txt当月:/wombat/2019/06/foo.txt 如果设置file属性为/wombat/foo.txt,上个月:/wombat/2019/05/foo.txt当月:/wombat/foo.txt
/wombat/foo.%d{yyyy-ww}.log 每周第一天滚动 文件命名规则与上类似
/wombat/foo%d{yyyy-MM-dd_HH}.log 按小时滚动 文件命名规则与上类似
/wombat/foo%d{yyyy-MM-dd_HH-mm}.log 按分钟滚动 文件命名规则与上类似
/wombat/foo%d{yyyy-MM-dd_HH-mm, UTC}.log 指定时区按分钟滚动 文件命名规则与上类似,只是指定了时区
/foo/%d{yyyy-MM,aux}/%d.log 按天滚动,归档日志文件在一个包含年和月文件夹里。 第一个%d起辅助作用,第二个%d由于没有指定日期和时间格式,默认为yyyy-MM-dd。

TimeBasedRollingPolicy支持归档日志文件自动压缩,如果fileNamePattern的值以.gz或者.zip结尾则可利用该特性。

文件命名格式 滚动计划 备注
/wombat/foo.%d.gz 按日滚动,归档日志文件会自动GZIP压缩 如果file属性没有设置,文件格式如下:昨天:/wombat/foo.2019-05-05.gz当天:/wombat/foo.2019-05-06 如果设置file属性为/wombat/foo.txt,文件格式如下:昨天:/wombat/foo.2019-05-05.gz当天:/wombat/foo.txt

滚动策略为TimeBasedRollingPolicy的RollingFileAppender

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logFile.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- 每日滚动 -->
      <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>

      <!-- 将30天的历史记录的总大小限制在3GB -->
      <maxHistory>30</maxHistory>
      <totalSizeCap>3GB</totalSizeCap>

    </rollingPolicy>

    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender> 

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>
  • Size and time based rolling policy(基于文件大小和时间的滚动策略)

通过这种策略可以按日期来归档日志文件,同时也可以限制每个日志文件的大小,示例如下:

<configuration>
  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>mylog.txt</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
      <!-- 每日滚动 -->
      <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
       <!-- 每个文件应该不超过100MB,保留60天的历史记录,但不超过20GB -->
       <maxFileSize>100MB</maxFileSize>    
       <maxHistory>60</maxHistory>
       <totalSizeCap>20GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>


  <root level="DEBUG">
    <appender-ref ref="ROLLING" />
  </root>

</configuration>

注意:%i转换符和%d在这里是必须的,当前时间周期内如果日志文件大小达到了maxFileSize,则会进行归档,文件名以从0开始的递增索引命名,%i表示从0开始递增索引。例如:mylog-2019-05-05.0.txt

  • FixedWindowRollingPolicy(固定窗口的滚动策略)

滚动时会根据固定窗口算法重命名文件,下面是FixedWindowRollingPolicy的子标签:

子标签 类型 备注
minIndex int 最小索引
maxIndex int 最大索引
fileNamePattern String 文件命名格式,必须包含%i转换符,用来表示被插入的当前窗口索引的位置。例如:如果文件命名格式为MyLogFile%i.log,minIndex、maxIndex分别被设为1、3,那么滚动时会产生名为MyLogFile1.log、MyLogFile2.log、MyLogFile3.log的三个日志文件。

假设minIndex被设为1,maxIndex被设为3,fileNamePatter被设为foo%i.log,file属性被设为foo.log,具体示例如下:

滚动次数 输出目标 归档日志文件 备注
0 foo.log - 没有产生滚动,日志输出文件为初始文件foo.log。
1 foo.log foo1.log 第一次滚动,foo.log重命名为foo1.log,新的foo.log被创建作为输出目标。
2 foo.log foo1.log, foo2.log 第二次滚动,foo1.log重命名为foo2.log,foo.log重命名为foo1.log,新的foo.log被创建作为输出目标。
3 foo.log foo1.log, foo2.log, foo3.log 第三次滚动,foo2.log重命名为foo3.log,foo1.log重命名为foo2.log,foo.log重命名为foo1.log,新的foo.log被创建作为输出目标。
4 foo.log foo1.log, foo2.log, foo3.log 后面滚动会先删除foo3.log,然后循环如上步骤。
<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>test.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>tests.%i.log.zip</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>3</maxIndex>
    </rollingPolicy>

    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>
触发策略

TriggerPolicy 实现负责指导 RollingFileAppender什么时候回滚,该接口如下:

package ch.qos.logback.core.rolling;

import java.io.File;
import ch.qos.logback.core.spi.LifeCycle;

public interface TriggeringPolicy<E> extends LifeCycle {

  public boolean isTriggeringEvent(final File activeFile, final <E> event);
}
  • SizeBasedTriggeringPolicy(限制大小)

SizeBasedTriggeringPolicy 会观察当前日志文件的大小,如果增长到指定值,会通知RollingFileAppender触发滚动。SizeBasedTriggeringPolicy只接受一个参数,也就是maxFileSize,默认值为10MB。maxFileSize选项的值可以是bytes、kilobytes、megabytes、gigabytes。例如:5000000、5000KB、5MB、2GB,前面三个等价。

下面是RollingFileAppender结合SizeBasedTriggeringPolicy配置示例:

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>test.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>test.%i.log.zip</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>3</maxIndex>
    </rollingPolicy>

    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

(6-2)Filter过滤器

在logback中,提供了两种类型的filter:regular过滤器和turbo过滤器。

规律型过滤器继承自 Filter抽象类,该类主要由带有ILoggingEvent参数的decide()方法组成。多个过滤器会基于三进制规则进行排序,每个过滤器的decide(ILoggingEvent event)方法依次会被调用,该方法返回FilterReply的枚举值,例如:DENY、NEUTRAL、ACCEPT。如果方法返回值为DENY,那么日志对象会被终止而不会被其它过滤器访问。如果方法返回值为NEUTRAL,那么下一个过滤器会进行处理,如果没有其余过滤器,那么日志会被正常处理。如果方法返回值为ACCEPT,那么日志对象会跳过其余过滤器被立即处理。

  • DENY:日志将立即被抛弃不再经过其他过滤器;
  • NEUTRAL:有序列表里的下个过滤器过接着处理日志;(该级别既不处理,也不抛弃,相当于没有任何处理,日志会被保存下来并在本appender被执行)
  • ACCEPT:日志会被立即处理,不再经过剩余过滤器。
1、自定义过滤器
package chapters.filters;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class SampleFilter extends Filter<ILoggingEvent> {

  @Override
  public FilterReply decide(ILoggingEvent event) {    
    if (event.getMessage().contains("sample")) {
      return FilterReply.ACCEPT;
    } else {
      return FilterReply.NEUTRAL;
    }
  }
}
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

    <filter class="chapters.filters.SampleFilter" />

    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger - %msg%n
      </pattern>
    </encoder>
  </appender>

  <root>
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
2、LevelFilter(级别过滤器)

LevelFilter基于匹配的具体级别过滤事件,如果日志事件的级别等于配置的级别,那么过滤器会接受或者拒绝日志事件,这取决于配置的onMatch和onMisMatch属性,如下:

<configuration>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>INFO</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger{30} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>
3、ThresholdFilter(阀值过滤器)

ThresholdFilter会过滤低于指定阀值的日志事件,对于等于或者大于阀值的日志事件,该过滤器会响应NEUTRAL,而对于低于阀值的日志事件,改过滤器会响应DENY。如下:

<configuration>
  <appender name="CONSOLE"
    class="ch.qos.logback.core.ConsoleAppender">
    <!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>INFO</level>
    </filter>
    <encoder>
      <pattern>
        %-4relative [%thread] %-5level %logger{30} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="CONSOLE" />
  </root>
</configuration>

(7)<logger>指定包的日志级别

用来设置某一个包或具体的某一个类的日志打印级别、以及指定 <appender><logger> 仅有一个name属性,一个可选的level和一个可选的addtivity属性。

可以包含零个或多个 <appender-ref> 元素,标识这个appender将会添加到这个loger

  • name: 用来指定受此loger约束的某一个包或者具体的某一个类。

  • level: 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL和OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。 如果未设置此属性,那么当前loger将会继承上级的级别。

  • addtivity: 是否向上级loger传递打印信息。默认是true。同<loger>一样,可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个loger。

<configuration>
    <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
    <logger name="org.springframework" level="INFO"></logger>
    <logger name="org.mybatis" level="INFO"></logger>
</configuration>    

常用 logger 配置

<!-- show parameters for hibernate sql 专为 Hibernate 定制 -->
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
<logger name="org.hibernate.SQL" level="DEBUG" />
<logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
<logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />

<!--myibatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>

(8)<root>根logger

它也是 <loger> 元素,但是它是根loger,是所有 <loger> 的上级。只有一个level属性,因为name已经被命名为”root”,且已经是最上级了。

  • level: 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL和OFF,不能设置为INHERITED或者同义词NULL。 默认是DEBUG。
<configuration>
    <!-- 最基础配置 -->
    <root level="debug">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="DEBUG_FILE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="WARN_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>

</configuration>

(9)<springProfile> 环境隔离

整体隔离

修改spring对应profile的配置文件

这里我们需要在spring不同的profile配置文件中,指定需要logback配置文件。

application.properties内容如下:

spring.profiles.active=dev
logging.config=classpath:logback.xml

application-dev.properties内容如下:

logging.config=classpath:logback-dev.xml

部分隔离

<configuration>
    <!-- 开发环境 -->
    <springProfile name="dev">
        <logger name="com.llayjun.millet.api" level="info"/>
    </springProfile>

    <!-- 生产环境 -->
    <springProfile name="prod">
        <logger name="com.llayjun.millet.api" level="error"/>
    </springProfile>
</configuration>

5、完整案例

以下配置适用于 lockback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
                 当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">
    <contextName>logback-spring</contextName>

    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
    <!-- 这边value配置成自己本地的日志地址 -->
    <property name="logging.path" value="E:\prod_logs" />

    <!--0. 日志格式和颜色渲染 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!--1. 输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--2. 输出到文档-->
    <!-- 不需要具体划分,则屏蔽INFO及以上 -->
    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${logging.path}/web_debug.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志归档 -->
            <fileNamePattern>${logging.path}/web-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${logging.path}/web_info.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${logging.path}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${logging.path}/web_warn.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logging.path}/web-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 2.4 level为 ERROR 日志,时间滚动输出  -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${logging.path}/web_error.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logging.path}/web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender>。<logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
        <logger name="org.springframework.web" level="info"/>
        <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
    -->

    <!--
        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
        第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
        【logging.level.org.mybatis=debug logging.level.dao=debug】
     -->

    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->
    <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
    <logger name="org.springframework" level="INFO"></logger>
    <logger name="org.mybatis" level="INFO"></logger>
    <logger name="org.apache.zookeeper" level="INFO"></logger>

    <!-- 4. 最终的策略 -->
    <!-- 4.1 开发环境:打印控制台-->
    <!-- 记住:日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
    <!-- 开发环境 -->
    <springProfile name="dev">
        <logger name="com.llayjun.millet.api" level="info"/>
    </springProfile>

    <!-- 生产环境 -->
    <springProfile name="prod">
        <logger name="com.llayjun.millet.api" level="error"/>
    </springProfile>

    <!-- 最基础配置 -->
    <root level="debug">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="DEBUG_FILE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="WARN_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>

</configuration>

6、日志按天归档

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="log" />
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 按照每天生成日志文件 -->
    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--<file>${LOG_HOME}/sms.log</file>-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/response.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>-->
    </appender>

    <!-- 日志输出级别 -->
    <root level="INFO">
        <!--输出到控制台-->
        <!--<appender-ref ref="STDOUT" />-->
        <!--输出到文件中-->
        <appender-ref ref="FILE" />
    </root>
</configuration>

三、log4j2

导入maven包

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.14.1</version>
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.14.1</version>
</dependency>

测试代码

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class LoggerTest {

    public static void main(String argv[]) {
        Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);

        logger.trace("trace level");
        logger.debug("debug level");
        logger.info("info level");
        logger.warn("warn level");
        logger.error("error level");
        logger.fatal("fatal level");

        logger.error("字符串拼接一:{},记录main执行:","logger");
        logger.error("字符串拼接二:","logger");

    }
}

  目录