相关推荐recommended
【日志框架】
作者:mmseoamin日期:2024-02-06

日志打印

  • 建议用{}占位而不是字符串拼接
  • 日志前先判断日志级别是否可用:
    1. 先根据等级过滤规则再决定写不写;
    2. 先往一个管道写了内容,但再经等级过滤丢弃,徒增开销。

    日志框架

    Slf4J

    Slf4J 不是底层日志框架,只是门面框架(抽象),需要配合jul、log4j、logback、log4j2等底层框架(真正干活的)使用。

    1. 避免日志对代码的耦合,更换日志框架时也不需改动任何代码。不论使用哪种底层框架时,在代码层面都一样。
    2. 避免引入第三方jar而其中日志框架不一致时需要同时维护不同的日志框架对应的配置文件。

    【日志框架】,在这里插入图片描述,第1张

    补充:更老的门面框架还有jcl, 所以会看到有程序应用 jcl + log4j 这种搭配。Slf4J 后采用 Slf4J + log4j,但一些 jcl + log4j 项目也想用Slf4J 时,可以通过引入 jcl-over-slf4j log桥接工具的依赖,将原本输出到jcl的日志输出重定向到 SLF4J。

    如果只用了slf4j,而没有使用任何底层框架,就会出现以下错误:

    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    SLF4J: Defaulting to no-operation (NOP) logger implementation
    SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
    
    log4j
    • 依赖
          
              log4j
              log4j
              1.2.17
           
      
    • 配置文件 log4j.properties
      log4j.rootLogger=info, stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
      log4j.appender.logfile=org.apache.log4j.FileAppender
      log4j.appender.logfile.File=target/spring.log
      log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
      log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
      
    • 代码
      import org.apache.log4j.Logger;
      //更多请阅读:https://www.yiibai.com/log4j/log4j_sample_program.html
      public class log4jExample{
      	static Logger log = Logger.getLogger(log4jExample.class.getName());
      	public static void main(String[] args) {
       	 if (log.isDebugEnabled()) {
               log.debug("### Hello this is an debug message");
      	 }
      	 log.info("### Hello this is an info message"); // 不支持占位符
      	 }
      }
      
      输出
      2022-07-27 21:10:03,358 INFO [org.example.log4jExample] - ### Hello this is an info message
      
      logback (原生实现 SLF4J)

      Logback 旨在作为流行的 log4j 项目的继承者,在 log4j 1.x 停止的地方接手。

      Logback 的架构非常通用,可以在不同的情况下应用。 目前,logback 分为三个模块,logback-core、logback-classic 和 logback-access。

      logback-core 模块为其他两个模块奠定了基础。

      logback-classic 模块可以同化为 log4j 1.x 的显着改进版本。 此外,logback-classic 原生实现了 SLF4J API。

      logback-access 模块与 Tomcat 和 Jetty 等 Servlet 容器集成,以提供 HTTP 访问日志功能。 请注意,您可以轻松地在 logback-core 之上构建自己的模块。

      • 依赖

            
                ch.qos.logback
                logback-classic
                1.2.3
            
        
      • 默认配置

        Logback 默认配置的步骤 参考:https://www.cnblogs.com/warking/p/5710303.html

        1. 尝试在 classpath下查找文件logback-test.xml;
        2. 如果文件不存在,则查找文件logback.xml;
        3. 如果两个文件都不存在,logback用BasicConfigurator自动对自己进行配置,这会导致记录输出到控制台。

        logback.xml

         	
         		 
             	 
                  %-4relative [%thread] %-5level %logger{35} - %msg %n 
             	 
           	 
           	
           	 
               
           	 
        		
        	
        
        • 代码

          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;
          public class LogbackExample {
          	static Logger log = LoggerFactory.getLogger(LogbackExample.class);
          	public static void main(String[] args) {
              	if (log.isDebugEnabled()) {
                  	log.debug("### Hello this is an debug message");
              	}
              	log.info("### Hello this is an info message"); // 不支持占位符
          	}
          }
          

          输出

          129  [main] INFO  org.example.LogbackExample - ### Hello this is an info message
          

          如果需要将日志按规则生成到文件,也可以在logback.xml中配置;logback.xml中各标签的含义,查阅上文。

          如图可以配置将日志信息同时实时输出到终端和离线输出到日志文件。

          【日志框架】,在这里插入图片描述,第2张

        • @Slf4j 注解

          能够少写两行代码,不用每次都在类的最前边写上:

          	private static final Logger logger = LoggerFactory.getLogger(this.XXX.class);
          

          需要 lombok依赖。如果是基于SpringBoot,因为默认加入了Slf4j-api和logback的依赖,所以只需要添加lombok的依赖即可。

             
                 org.projectlombok
                 lombok
                 1.16.10
             
          
          • 代码
            import lombok.extern.slf4j.Slf4j;
            @Slf4j
            public class SLF4JExample {
                public static void main(String[] args) {
                    if (log.isDebugEnabled()) {
                        log.debug("### Hello this is an debug message");
                    }
                    log.info("### Hello this is an info message"); // log 由lombok提供,如报错是idea的问题
                }
            }
            
            log4j 适配 Slf4j
            • 依赖
                 
                     org.slf4j
                     slf4j-log4j12
                     1.7.28
                 
              

              只需要依赖 slf4j-log4j12,它自身依赖log4j 和 slf4j-api 两个包。

              • 配置

                由于底层框架仍然使用的是log4j,仍然需要 配置文件: log4j.properties

                log4j.rootLogger=info, stdout
                log4j.appender.stdout=org.apache.log4j.ConsoleAppender
                log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
                log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
                log4j.appender.logfile=org.apache.log4j.FileAppender
                log4j.appender.logfile.File=target/spring.log
                log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
                log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
                
              • 代码

                import org.slf4j.Logger;
                import org.slf4j.LoggerFactory;
                public class LogSlf4jExample {
                    static Logger log = LoggerFactory.getLogger(LogSlf4jExample.class);
                    public static void main(String[] args) {
                        if (log.isDebugEnabled()) {
                            log.debug("### Hello this is an debug message");
                        }
                        log.info("### Hello this is an info message"); // 不支持占位符
                    }
                }
                

                在代码层面已经实现和使用logback时一样了,都是从 org.slf4j.LoggerFactory 这个包下 getLogger来获取 Logger 对象。

                当然也可以使用 @Slf4j 注解的方法。代码是一样的,无法看出底层框架是log4j还是logback。