【日志框架】

日志打印

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

日志框架

Slf4J

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

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

补充:更老的门面框架还有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
  • 依赖

    xml 复制代码
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency> 
  • 配置文件 log4j.properties

    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
  • 代码

    java 复制代码
    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 之上构建自己的模块。

  • 依赖

    xml 复制代码
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
  • 默认配置

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

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

    logback.xml

xml 复制代码
 	<configuration>
 		<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
     	<encoder> 
          <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern> 
     	</encoder> 
   	</appender> 
   	
   	<root level="INFO"> 
      <appender-ref ref="STDOUT" /> 
   	</root> 

		<logger name="com.apache.ibatis" level="DEBUG"/>
	</configuration>
  • 代码

    java 复制代码
    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中各标签的含义,查阅上文。

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

  • @Slf4j 注解

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

复制代码
	private static final Logger logger = LoggerFactory.getLogger(this.XXX.class);

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

xml 复制代码
   <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <version>1.16.10</version>
   </dependency>
  • 代码
java 复制代码
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
  • 依赖
xml 复制代码
   <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-log4j12</artifactId>
       <version>1.7.28</version>
   </dependency>

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

  • 配置

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

    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
  • 代码

    java 复制代码
    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。

相关推荐
海兰15 分钟前
使用 Spring AI 打造企业级 RAG 知识库第二部分:AI 实战
java·人工智能·spring
历程里程碑33 分钟前
二叉树---二叉树的中序遍历
java·大数据·开发语言·elasticsearch·链表·搜索引擎·lua
小信丶1 小时前
Spring Cloud Stream EnableBinding注解详解:定义、应用场景与示例代码
java·spring boot·后端·spring
无限进步_1 小时前
【C++】验证回文字符串:高效算法详解与优化
java·开发语言·c++·git·算法·github·visual studio
亚历克斯神1 小时前
Spring Cloud 2026 架构演进
java·spring·微服务
七夜zippoe1 小时前
Spring Cloud与Dubbo架构哲学对决
java·spring cloud·架构·dubbo·配置中心
海派程序猿1 小时前
Spring Cloud Config拉取配置过慢导致服务启动延迟的优化技巧
java
阿维的博客日记1 小时前
为什么不逃逸代表不需要锁,JIT会直接删掉锁
java
William Dawson1 小时前
CAS的底层实现
java
九英里路1 小时前
cpp容器——string模拟实现
java·前端·数据结构·c++·算法·容器·字符串