日志简介

  • 日志的作用的就是取代System.out.println()
  • 有如下优点:
  1. 可以设置输出样式,如添加信息类别(错误,备注信息…) ,自动添加时间信息,出错方法等信息
  2. 可以设置输出级别,禁止某些级别输出。例如,只输出错误日志;
  3. 可以被重定向到文件,这样可以在程序运行结束后查看日志;
  4. 可以按包名控制日志级别,只输出某些包打的日志;
  5. 可以…

  • 一般为四种类别输出:

    • info
    • warn
    • error

    • 日志体系

      日志框架类别

      记录型日志框架

  • 记录型日志框架是日志功能的具体实现

  1. Jul (Java Util Logging):JDK中的日志记录工具,也常称为JDKLog、jdk-logging,自Java1.4以来的官方日志实现。
  2. Log4j:Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。
  3. Log4j2:一个具体的日志实现框架,是Log4j 1的下一个版本,与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1
  4. Logback:一个具体的日志实现框架,和Slf4j是同一个作者,但其性能更好(推荐使用)。

    门面型日志框架

  • 门面型日志框架是日志接口或者规范,使用时还是调用记录型日志。
    • 有的门面型日志也提供了简单的日子实现功能,为了在无第三方记录日志可调时以使用日志
  1. JCL:Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging
    1. jcl默认的配置:如果能找到Log4j 则默认使用log4j实现,如果没有则使用jul(jdk自带的) 实现,再没有则使用jcl内部提供的SimpleLog实现。
    • 日志 - 图1
  2. SLF4J:是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)
    1. slf4j自己也有一个简易的实现,但是需要额外引入slf4j-simple

关系与选择

  • log4j是最早的,之后sun公司为了竞争推出了jul
  • 因为从一个日志框架切换到另外一个,可能需要修改大量的代码,为了减少更改,将这些日志api抽象出接口,这样以后调用的时候,就调用这些接口
    • 由此诞生的就是jcl

  • jul性能一般,log4j也有性能问题且停止维护,建议使用 Logback 或者 Log4j2。
  • 因为logback与slf4j是同一个作者,兼容性很好。logback性能又强,**推荐使用logback+slf4j**

    • 同时logback完全免费

      使用注意

  • 日志频繁爆漏洞,所以

    • 一定要使用门面框架。
    • 只添加一个日志实现
    • 日志实现坐标应该设置 optional 并使⽤ runtime scope,如
      • 设置 optional 为 true,依赖不会传递,这样如果你是个 lib 项⽬,然后别的项目使⽤了你这个 lib,不会被引入不想要的 Log Implementation 依赖;
      • scope 设置为 runtime,是为了防⽌开发⼈员在项⽬中直接使⽤ Log Implementation 中的类,强制约束开发人员使⽤ Facade 接口。
    • 更多…链接
      1. <dependency>
      2. <groupId>org.apache.logging.log4j</groupId>
      3. <artifactId>log4j-core</artifactId>
      4. <version>${log4j.version}</version>
      5. <scope>runtime</scope>
      6. <optional>true</optional>
      7. </dependency>
      8. <dependency>
      9. <groupId>org.apache.logging.log4j</groupId>
      10. <artifactId>log4j-slf4j-impl</artifactId>
      11. <version>${log4j.version}</version>
      12. <scope>runtime</scope>
      13. <optional>true</optional>
      14. </dependency>

      JDK Logging (JUL)

  • Java标准库内置了日志包java.util.logging

  • 使用Java标准库内置的Logging有以下局限:
    • Logging系统在JVM启动时读取配置文件并完成初始化,一旦开始运行main()方法,就无法修改配置;
    • 配置不太方便,需要在JVM启动时传递参数-Djava.util.logging.config.file=
  • 会额外输出时间``类``方法名``日志类别
  • JDK的Logging定义了7个日志级别,从严重到普通。默认级别是INFO,INFO级别以下的日志,不会被打印出来
    • SEVERE
    • WARNING
    • INFO
    • CONFIG
    • FINE
    • FINER
    • FINEST
  • 传入的类名是用于打印到输出日志的,貌似需要进行配置才生效,直接输出时都是输出日志语句当前类和当前方法

    1. public class Hello {
    2. public static void main(String[] args) {
    3. Logger logger = Logger.getGlobal();
    4. 或者
    5. Logger logger = Logger.getLogger(类名.class.getName());
    6. logger.info("start process...");
    7. logger.warning("memory is running out...");
    8. logger.fine("ignored.");
    9. logger.severe("process will be terminated...");
    10. }
    11. }
    12. Mar 02, 2019 6:32:13 PM Hello main
    13. 信息: start process...
    14. Mar 02, 2019 6:32:13 PM Hello main
    15. 警告: memory is running out...
    16. Mar 02, 2019 6:32:13 PM Hello main
    17. 严重: process will be terminated...

    JCL

  • 这里提下JCL只是为了看到方法和类能更快的明白这是用的JCL ,不至于不认识

    • 同sjlf4j用法差不多,不同之处就是Log变成了Logger,LogFactory变成了LoggerFactory
  • image.png

    SLF4J

  • slf4j使用方法和jcl差不多,下面是sjf4j使用

  • **日志对象必须在类里创建,否则**getClass()报错
    • 可以在类上配置@Slf4j注解自动创建一个名称为log的Logger
  • slf4j支持占位符拼接字符串
  • sjf4j会自动寻找日志实现
    • 在springboot项目中默认就集成了**logback**且是默认日志,无需引入。slf4j会自动使用logback
    • 平常springboot项目启动的信息其实就是logback信息格式
    • spring-boot-starter-test中附带了slf4j的包,也无需再引入
    • 多个实现日志时如果存在logback,会自动选择logback,其他日志实现的优先级不清楚
  • 注意导入的**Logger****LoggerFactory**都是**org.slf4j**里的,不是**om.sun.org.slf4j**里的

image.png

  1. //@Slf4j
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. class Main{
  5. final Logger logger = LoggerFactory.getLogger(getClass());
  6. main(){
  7. int score = 99;
  8. p.setScore(score);
  9. logger.info("Set score {} for Person {} ok.", score, p.getName());
  10. }
  11. }
  12. 输出信息格式如下:
  13. 11:18:09.701 [main] INFO c.x.l.SpringBootDemoLogbackApplication - set score ........

LogBack

  • springboot中logback可不配置就能使用,因为springboot默认的日志框架就是logback,集成了
  • 如果要使用配置文件,需要在springboot的默认配置文件中添加如下配置

    1. logging:
    2. # 设置logback.xml位置
    3. config: classpath:logback-spring.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    <property name="FILE_ERROR_PATTERN"
              value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} %file:%line: %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
      <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
          <filter class="ch.qos.logback.classic.filter.LevelFilter">
              <level>INFO</level>
          </filter>
          <encoder>
              <pattern>${CONSOLE_LOG_PATTERN}</pattern>
              <charset>UTF-8</charset>
          </encoder>
      </appender>
    
      <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高, 所以我们使用下面的策略,可以避免输出 Error 的日志-->
          <filter class="ch.qos.logback.classic.filter.LevelFilter">
              <!--过滤 Error,这一部没有看懂是什么作用-->
              <level>ERROR</level>    
              <!--匹配到就禁止-->
              <onMatch>DENY</onMatch>
              <!--没有匹配到就允许-->
              <onMismatch>ACCEPT</onMismatch>
          </filter>
          <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File> 的日志都是当天的。-->
          <!--<File>logs/info.demo-logback.log</File>-->
          <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
              <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
              <FileNamePattern>logs/demo-logback/info.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
              <!--只保留最近90天的日志-->
              <maxHistory>90</maxHistory>
              <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
              <!--<totalSizeCap>1GB</totalSizeCap>-->
              <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                  <!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
                  <maxFileSize>2MB</maxFileSize>
              </timeBasedFileNamingAndTriggeringPolicy>
          </rollingPolicy>
          <!--<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">-->
          <!--<maxFileSize>1KB</maxFileSize>-->
          <!--</triggeringPolicy>-->
          <encoder>
              <pattern>${FILE_LOG_PATTERN}</pattern>
              <charset>UTF-8</charset> <!-- 此处设置字符集 -->
          </encoder>
      </appender>
    
      <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter-->
          <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
              <level>Error</level>
          </filter>
          <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File> 的日志都是当天的。-->
          <!--<File>logs/error.demo-logback.log</File>-->
          <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
              <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间,下面会生成一个以error.created_on_名称开头的-->
              <FileNamePattern>D:/logs/demo-logback/error.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
              <!--只保留最近90天的日志-->
              <maxHistory>90</maxHistory>
              <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                  <!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
                  <maxFileSize>2MB</maxFileSize>
              </timeBasedFileNamingAndTriggeringPolicy>
          </rollingPolicy>
          <encoder>
              <pattern>${FILE_ERROR_PATTERN}</pattern>
              <charset>UTF-8</charset> <!-- 此处设置字符集 -->
          </encoder>
      </appender>
    
      <root level="info">
          <appender-ref ref="CONSOLE"/>
          <appender-ref ref="FILE_INFO"/>
          <appender-ref ref="FILE_ERROR"/>
      </root>
    </configuration>
    

    springboot控制台日志无颜色

  • 在启动的configuration配置里的vm option设置为-Dspring.output.ansi.enabled=ALWAYS

  • image.png