前言
在开发 Java 应用时,日志记录是不可或缺的一部分。日志可以记录应用的运行状态、错误信息和调试信息,帮助开发者快速定位和解决问题。Spring Boot 项目默认集成了 SLF4J 和 Logback,使得日志配置变得简单而灵活。本文将详细介绍如何在 Spring Boot 项目中配置 SLF4J 和 Logback,包括基本的日志配置、日志文件的输出路径、日志级别、日志格式和环境区分配置。
1. 引入依赖
Spring Boot 项目默认已经包含了 SLF4J 和 Logback 的依赖,如果你使用的是 Spring Initializr 初始化的项目,通常不需要额外添加依赖。如果你的项目中没有这些依赖,可以在pom.xml
中添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
2. 基本日志配置
Spring Boot 允许通过application.yml
或application.properties
文件进行简单的日志配置。以下是一个基本的配置示例:
application.yml
logging:
level:
root: INFO
com.example.yourpackage: DEBUG # 你的项目包路径
file:
name: application.log
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
application.properties
logging.level.root=INFO
logging.level.com.example.yourpackage=DEBUG # 你的项目包路径
logging.file.name=application.log
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
以上配置将日志级别设置为INFO
,并为你的项目包设置为DEBUG
级别。同时,设置了日志文件的名称和日志输出的格式。
3. 配置 Logback
Logback 是 SLF4J 的一个实现,提供了更强大的日志配置功能。你可以通过logback-spring.xml
文件进行更详细的日志配置。以下是一个示例配置文件:
logback-spring.xml
<configuration>
<!-- 定义日志文件的路径和名称 -->
<property name="LOG_PATH" value="/var/log/yourapp" />
<property name="LOG_FILE" value="${LOG_PATH}/application.log" />
<!-- 控制台日志输出配置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 文件日志输出配置 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件的滚动策略 -->
<fileNamePattern>${LOG_PATH}/application-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory> <!-- 保留30天的日志文件 -->
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 指定日志级别 -->
<logger name="org.apache.ibatis" level="DEBUG">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</logger>
<logger name="com.example.yourpackage" level="DEBUG">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</logger>
<!-- 根日志级别 -->
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
4. 环境区分配置
在实际项目中,不同环境(如开发环境、测试环境、生产环境)的日志配置需求可能会有所不同。Spring Boot 支持多配置文件来区分不同环境。你可以在src/main/resources
目录下创建多个配置文件,例如:
application-dev.yml
:开发环境配置application-test.yml
:测试环境配置application-prod.yml
:生产环境配置
application-dev.yml
spring:
profiles: dev
logging:
level:
root: DEBUG
com.example.yourpackage: DEBUG
file:
name: application-dev.log
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
application-test.yml
spring:
profiles: test
logging:
level:
root: INFO
com.example.yourpackage: INFO
file:
name: application-test.log
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
application-prod.yml
spring:
profiles: prod
logging:
level:
root: WARN
com.example.yourpackage: INFO
file:
path: /var/log/yourapp
name: application-prod.log
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} %thread %-5level %logger{36} - %msg%n"
启动应用时,可以通过命令行参数指定使用哪个配置文件:
java -jar -Dspring.profiles.active=prod yourapp.jar
5. 日志文件路径权限
确保 Spring Boot 应用在服务器上有写日志文件的权限。你可以通过以下命令检查和修改目录权限:
# 检查目录权限
ls -ld /var/log/yourapp
# 修改目录权限
sudo chown -R youruser:yourgroup /var/log/yourapp
sudo chmod -R 755 /var/log/yourapp
6. 日志文件查看
启动应用后,检查日志文件是否正确生成并记录了日志。你可以在服务器上使用以下命令查看日志文件:
# 查看日志文件
tail -f /var/log/yourapp/application-prod.log
7. 使用自定义拦截器
如果你需要在日志中记录特定的信息,例如 SQL 执行时间,可以使用自定义拦截器。以下是一个示例拦截器:
SqlTimingInterceptor.java
package com.example.yourpackage.interceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.plugin.*;
import java.sql.Statement;
import java.util.Properties;
@Intercepts(@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}))
public class SqlTimingInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
long start = System.currentTimeMillis();
try {
return invocation.proceed();
} finally {
long end = System.currentTimeMillis();
long timeTaken = end - start;
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
String sql = (String) SystemMetaObject.forObject(statementHandler).getValue("delegate.boundSql.sql");
Log log = Slf4jImpl.create(this.getClass());
log.debug("SQL: " + sql);
log.debug("执行时间: " + timeTaken + " ms");
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 可以设置一些自定义属性
}
}
MyBatisConfig.java
package com.example.yourpackage.config;
import com.example.yourpackage.interceptor.SqlTimingInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@MapperScan("com.example.yourpackage.mapper")
public class MyBatisConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/yourdb");
dataSource.setUsername("yourusername");
dataSource.setPassword("yourpassword");
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
// 注册拦截器
SqlTimingInterceptor sqlTimingInterceptor = new SqlTimingInterceptor();
Properties properties = new Properties();
properties.setProperty("someProperty", "someValue"); // 根据需要设置拦截器属性
sqlTimingInterceptor.setProperties(properties);
factoryBean.setPlugins(new Interceptor[]{sqlTimingInterceptor});
return factoryBean.getObject();
}
}