Intellij idea中使用SLF4J+log4j做日志记录

本文介绍如何在IntelliJ IDEA中使用SLF4J结合log4j进行日志记录配置。涵盖Maven项目和Spring MVC Web项目的配置步骤,并比较了SLF4J与其他日志框架的优势。

Intellij idea中使用SLF4J+log4j做日志记录

一、  简介

SLF4J (Simple Logging Facade for Java) 不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统。
实际上,SLF4J所提供的核心API是一些接口以及一个LoggerFactory的工厂类。从某种程度上,SLF4J有点类似JDBC,不过比JDBC更简单,在JDBC中,你需要指定驱动程序,而在使用SLF4J的时候,不需要在代码中或配置文件中指定你打算使用那个具体的日志系统。如同使用JDBC基本不用考虑具体数据库一样,SLF4J提供了统一的记录日志的接口,只要按照其提供的方法记录即可,最终日志的格式、记录级别、输出方式等通过具体日志系统的配置来实现,因此可以在应用中灵活切换日志系统。

二 应用程序中使用方法及配置

1 先在idea中用新建一个maven的空项目,建好的项目结构如图:


部分文件是后面加的,结构就是这样子的

 2 我们添加一个class(testDemo.class),并添加main方法,代码如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by hqj on 2017/7/25.
 */
public class testDemo {

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

    public static void main(String[] args) {
        System.out.println("This is println message. yeah");

        // 记录debug级别的信息
        logger.debug("This is debug message.");
        // 记录info级别的信息
        logger.info("This is info message.");
        // 记录error级别的信息
        logger.error("This is error message.");

    }
}

3 添加相应的包,在pom.xml中添加相应的依赖,然后点击右下角的import changes 即可自动导入相应的包

pom.xml添加的内容如下:

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.2</version>
    </dependency>
</dependencies>

4 在src>main>resources下添加 log4j.properties文件,内容如下:

### 设置###
log4j.rootLogger = debug,stdout,D,E,I

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出INFO 级别以上的日志到=E://logs/error.log ###
log4j.appender.I = org.apache.log4j.DailyRollingFileAppender
log4j.appender.I.File =E://logs/info.log
log4j.appender.I.Append = true
log4j.appender.I.Threshold = INFO
log4j.appender.I.layout = org.apache.log4j.PatternLayout
log4j.appender.I.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

其中路径部分可更改,

5 启动程序看是否能输出日志,启动时程序会弹出让配置启动类,设为testDemo即可,程序正常启动,且在相应的目录可以看到产生了日志文件。

三 spring+mvc web项目使用及配置方法

1 新建好一个 spring mvc web项目,过程略,可参见另一篇 去看看

2 在pom.xml中添加相应的依赖,然后点击右下角的import changes导入相应的包,加的内容如下:

<dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.2</version>
    </dependency>

3 在web.xml中加入如下内容:

<context-param>
    <param-name>log4jConfigLocation</param-name>
    <!--<param-value>classpath:/log4j/log4j.xml</param-value>-->
    <param-value>/WEB-INF/config/log4j.properties</param-value>
  </context-param>
  <!-- 加载log4j配置文件 -->
  <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
如上内容中有一个注释了的,原来是按这么写的,发现不行,改成 <param-value>/WEB-INF/config/log4j.properties</param-value> 这样即可

4 在web-inf下建config文件夹,再在config下添加log4j.properties文件,内容如下:

### 设置###
log4j.rootLogger = debug,stdout,D,E,I

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出INFO 级别以上的日志到=E://logs/error.log ###
log4j.appender.I = org.apache.log4j.DailyRollingFileAppender
log4j.appender.I.File =E://logs/info.log
log4j.appender.I.Append = true
log4j.appender.I.Threshold = INFO
log4j.appender.I.layout = org.apache.log4j.PatternLayout
log4j.appender.I.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

5 至引配置完成,启动tomcat,运行程序,发现日志如期输出。

上面两个demo都能正常运行,idea版本为IntelliJ IDEA 2017.1.4 x64。本篇只是测试日志能否正常记录,代码及配置可以再优化,后续再修改。

四 SLF4J对比Log4J,logback和java.util.Logging的优势


正如我之前说的,在你的代码中使用SLF4J写日志语句的主要出发点是使得你的程序独立于任意特定的日志类库,依赖于特定类可能需要不同与你已有的配置,并且导致更多维护的麻烦。但除此之外,还要一个SLF4J API的特性使得我坚持使用SLF4J而抛弃我长期间钟爱的Lof4j的理由,是被称为占位符(place holder),在代码中表示为“{}”的特性。占位符是一个非常类似于在String的format()方法中的%s,因为它会在运行时被某个提供的实际字符串所替换。这不仅降低了你代码中字符串连接次数,而且还节省了新建的String对象。即使你可能没需要那些对象,但这个依旧成立,取决于你的生产环境的日志级别,例如在DEBUG或者INFO级别的字符串连接。因为String对象是不可修改的并且它们建立在一个String池中,它们消耗堆内存( heap memory)而且大多数时间他们是不被需要的,例如当你的应用程序在生产环境以ERROR级别运行时候,一个String使用在DEBUG语句就是不被需要的。通过使用SLF4J,你可以在运行时延迟字符串的建立,这意味着只有需要的String对象才被建立。而如果你已经使用log4j,那么你已经对于在if条件中使用debug语句这种变通方案十分熟悉了,但SLF4J的占位符就比这个好用得多。

这是你在Log4j中使用的方案,但肯定这一点都不有趣并且降低了代码可读性因为增加了不必要的繁琐重复代码(boiler-plate code):

if (logger.isDebugEnabled()) {
    logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
}

另一方面,如果你使用SLF4J的话,你可以得到在极简洁的格式的结果,就像以下展示的一样:

logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

在SLF4J,我们不需要字符串连接而且不会导致暂时不需要的字符串消耗。取而代之的,我们在一个以占位符和以参数传递实际值的模板格式下写日志信息。你可能会在想万一我有很个参数怎么办?嗯,那么你可以选择使用变量参数版本的日志方法或者用以Object数组传递。这是一个相当的方便和高效方法的打日志方法。记住,在生产最终日志信息的字符串之前,这个方法会检查一个特定的日志级别是不是打开了,这不仅降低了内存消耗而且预先降低了CPU去处理字符串连接命令的时间。这里是使用SLF4J日志方法的代码,来自于slf4j-log4j12-1.6.1.jar中的Log4j的适配器类Log4jLoggerAdapter。


public void debug(String format, Object arg1, Object arg2) {
    if (logger.isDebugEnabled()) {
        FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
        logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
    }
}

同时,我们也很值得知道打日志是对应用程序的性能有着很大影响的,在生产环节上只进行必要的日志记录是我们所建议的。


--- end ---



### 解决 IntelliJ IDEASLF4J 版本冲突问题 SLF4J(Simple Logging Facade for Java)是一个日志门面框架,用于统一不同的日志实现(如 Logback、Log4j、java.util.logging 等)。在使用 Maven 或 Gradle 构建项目时,多个依赖库可能引入不同版本的 SLF4J 绑定(binding),从而导致版本冲突。这类冲突通常表现为控制台警告信息: ``` SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/path/to/slf4j-log4j12-1.7.30.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/path/to/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. ``` #### 1. **明确冲突来源** 首先需要确定哪些依赖引入了 SLF4J 的绑定。Maven 用户可以使用以下命令查看依赖树: ```bash mvn dependency:tree ``` 查找输出中包含 `slf4j` 的条目,特别是 `slf4j-api` 和其绑定实现(如 `slf4j-log4j12`、`logback-classic` 等)。 IntelliJ IDEA 提供了内置的依赖分析工具,点击左上角的 **Conflicts** 选项,在输入框中输入 `slf4j`,IDE 会自动过滤出所有涉及 `slf4j-api` 的依赖,并展示版本冲突情况及根源依赖[^2]。 #### 2. **排除多余的绑定依赖** 解决冲突的核心原则是:**只保留一个 SLF4J 绑定实现**。常见的绑定包括: - `slf4j-simple.jar` - `slf4j-nop.jar` - `slf4j-log4j12.jar` - `slf4j-jdk14.jar` - `logback-classic.jar` 如果项目中已经引入了 `logback-classic`,则应排除其他绑定依赖。例如,在 Maven 的 `pom.xml` 中进行如下配置: ```xml <dependency> <groupId>some.group</groupId> <artifactId>some-artifact</artifactId> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> ``` #### 3. **指定统一版本** 为了防止多个版本的 `slf4j-api` 被引入,可以在 `pom.xml` 中使用 `<dependencyManagement>` 显式声明统一版本: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version> </dependency> </dependencies> </dependencyManagement> ``` #### 4. **Spring Boot 项目中的特殊处理** 若使用的是 Spring Boot 项目,默认的日志实现是 Logback(即 `logback-classic`)。若想切换为 Log4j2,则需替换默认的 starter: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> ``` 这样可确保 SLF4J 使用 Log4j2 作为底层实现[^4]。 #### 5. **验证与排查** 修改完依赖后,重新构建项目并运行,观察控制台是否仍然提示 SLF4J 冲突。也可以再次运行 `mvn dependency:tree` 验证是否已排除多余绑定。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值