本文目录导读:

我将为您提供一个全面的Java日志框架案例,涵盖主流日志框架的使用和最佳实践。
常用日志框架对比
<!-- pom.xml 依赖配置 -->
<dependencies>
<!-- SLF4J API - 日志门面 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<!-- Logback - 日志实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
<!-- Log4j2 - 替代Log4j 1.x -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.20.0</version>
</dependency>
<!-- 兼容旧版log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.36</version>
</dependency>
<!-- Lombok的@Slf4j注解(可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
基础使用案例
1 标准SLF4J使用
package com.example.logging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 日志使用基础案例
*/
public class BasicLoggingExample {
// 推荐使用private static final
private static final Logger logger = LoggerFactory.getLogger(BasicLoggingExample.class);
public void demonstrateLogLevels() {
// 不同级别的日志
logger.trace("这是TRACE级别日志");
logger.debug("这是DEBUG级别日志,用户ID: {}", 1001);
logger.info("这是INFO级别日志");
logger.warn("这是WARN级别日志");
logger.error("这是ERROR级别日志", new RuntimeException("示例异常"));
}
public void demonstrateParameterizedLogging() {
String username = "张三";
int age = 25;
// 使用占位符,避免字符串拼接
logger.debug("用户{},年龄{},正在登录系统", username, age);
// 只有debug级别启用时才执行方法
if (logger.isDebugEnabled()) {
logger.debug("复杂的调试信息: " + expensiveMethod());
}
}
private String expensiveMethod() {
// 模拟昂贵操作
return "计算结果";
}
// 使用Lombok简化
// @Slf4j
public static void main(String[] args) {
BasicLoggingExample example = new BasicLoggingExample();
example.demonstrateLogLevels();
example.demonstrateParameterizedLogging();
}
}
2 MDC(Mapped Diagnostic Context)使用
package com.example.logging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import java.util.UUID;
/**
* MDC用于跟踪请求上下文
*/
public class MDCExample {
private static final Logger logger = LoggerFactory.getLogger(MDCExample.class);
public void processRequest(String userId) {
// 在请求开始时设置MDC
MDC.put("requestId", UUID.randomUUID().toString());
MDC.put("userId", userId);
try {
logger.info("开始处理用户请求");
// 业务逻辑
doBusinessLogic();
logger.info("请求处理完成");
} catch (Exception e) {
logger.error("处理请求失败", e);
} finally {
// 确保清理MDC,避免内存泄漏
MDC.clear();
}
}
private void doBusinessLogic() {
logger.debug("执行业务逻辑,当前用户: {}", MDC.get("userId"));
}
}
Logback配置案例
1 logback.xml 完整配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 定义属性 -->
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
<property name="LOG_PATH" value="./logs"/>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 滚动文件 - 按大小 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/archive/application-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 错误日志单独文件 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/error.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/archive/error-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>512</queueSize>
<discardingThreshold>0</discardingThreshold>
<appender-ref ref="FILE"/>
</appender>
<!-- 不同包的日志级别设置 -->
<logger name="org.springframework" level="WARN"/>
<logger name="com.example" level="DEBUG"/>
<!-- 根日志级别 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ASYNC_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</configuration>
2 动态配置示例
package com.example.logging;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;
public class DynamicLogLevelExample {
public void changeLogLevel(String packageName, String level) {
Object obj = LoggerFactory.getILoggerFactory();
if (obj instanceof LoggerContext) {
LoggerContext context = (LoggerContext) obj;
ch.qos.logback.classic.Logger logger = context.getLogger(packageName);
// 动态修改日志级别
logger.setLevel(Level.toLevel(level));
}
}
}
Log4j2配置案例
1 log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
<Property name="LOG_PATH">./logs</Property>
</Properties>
<Appenders>
<!-- 控制台 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %highlight{%-5level} %style{%logger{36}}{cyan} - %msg%n"/>
</Console>
<!-- 滚动文件 -->
<RollingFile name="RollingFile" fileName="${LOG_PATH}/app.log"
filePattern="${LOG_PATH}/app-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="50MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingFile>
<!-- 异步文件 -->
<Async name="AsyncFile">
<AppenderRef ref="RollingFile"/>
<BufferSize>1024</BufferSize>
</Async>
</Appenders>
<Loggers>
<Logger name="org.springframework" level="WARN"/>
<Logger name="com.example" level="DEBUG"/>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="AsyncFile"/>
</Root>
</Loggers>
</Configuration>
高级应用案例
1 日志分类使用
package com.example.logging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 业务日志案例
*/
public class BusinessLogExample {
private static final Logger BUSINESS_LOGGER = LoggerFactory.getLogger("business");
private static final Logger SECURITY_LOGGER = LoggerFactory.getLogger("security");
private static final Logger OPERATION_LOGGER = LoggerFactory.getLogger("operation");
public void businessOperation(String orderId, String userId) {
// 业务日志
BUSINESS_LOGGER.info("用户{}创建订单:{}", userId, orderId);
// 安全审计日志
SECURITY_LOGGER.info("用户操作:{} 执行创建订单操作,订单号:{}", userId, orderId);
// 操作日志
OPERATION_LOGGER.info("订单创建成功 | 操作人:{} | 订单号:{} | 时间:{}",
userId, orderId, System.currentTimeMillis());
}
public void throwException() {
try {
int result = 10 / 0;
} catch (Exception e) {
// 记录异常时的标准做法
logger.error("计算异常,参数: a={}, b={}", 10, 0, e);
}
}
private static final Logger logger = LoggerFactory.getLogger(BusinessLogExample.class);
}
2 日志埋点与性能监控
package com.example.logging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PerformanceLogExample {
private static final Logger logger = LoggerFactory.getLogger(PerformanceLogExample.class);
public void logWithTime() {
long start = System.currentTimeMillis();
try {
// 模拟业务逻辑
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
long cost = System.currentTimeMillis() - start;
// 性能日志,超过阈值告警
if (cost > 50) {
logger.warn("方法执行耗时过长: {} ms", cost);
} else {
logger.debug("方法执行耗时: {} ms", cost);
}
}
}
// 使用AOP实现方法性能监控
// @Around("execution(* com.example..*.*(..))")
// public Object logPerformance(ProceedingJoinPoint pjp) throws Throwable {
// long start = System.currentTimeMillis();
// Object result = pjp.proceed();
// long cost = System.currentTimeMillis() - start;
// logger.info("方法 {} 执行耗时: {}ms", pjp.getSignature(), cost);
// return result;
// }
}
3 Spring Boot配置
# application.yml
logging:
level:
root: INFO
com.example: DEBUG
org.springframework: WARN
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
file:
name: ./logs/spring-boot-application.log
max-size: 10MB
max-history: 30
4 审计日志
package com.example.logging;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class AuditLogService {
private static final Logger auditLogger = LoggerFactory.getLogger("AUDIT");
private final ObjectMapper objectMapper = new ObjectMapper();
public void logAction(String user, String action, Object data) {
AuditLog auditLog = new AuditLog();
auditLog.setUserId(user);
auditLog.setAction(action);
auditLog.setTimestamp(System.currentTimeMillis());
try {
String json = objectMapper.writeValueAsString(data);
auditLog.setData(json);
} catch (Exception e) {
auditLog.setData("序列化失败");
}
// 写入审计日志
auditLogger.info("AUDIT - {}", toJsonString(auditLog));
}
private String toJsonString(Object obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (Exception e) {
return obj.toString();
}
}
static class AuditLog {
private String userId;
private String action;
private long timestamp;
private String data;
// getters and setters...
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
public String getAction() { return action; }
public void setAction(String action) { this.action = action; }
public long getTimestamp() { return timestamp; }
public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
public String getData() { return data; }
public void setData(String data) { this.data = data; }
}
}
最佳实践总结
package com.example.logging;
/**
* 日志最佳实践总结
*/
public class LoggingBestPractices {
/**
* 1. 使用SLF4J门面而不是直接使用具体实现
* 2. 使用参数化日志,避免字符串拼接
* 3. 正确处理异常日志
* 4. 合理设置日志级别
* 5. 清理MDC上下文
*/
private static final org.slf4j.Logger logger =
org.slf4j.LoggerFactory.getLogger(LoggingBestPractices.class);
public void rules() {
// 1. 使用占位符而不是字符串拼接
String name = "test";
int id = 100;
logger.debug("用户: {}, ID: {}", name, id); // 正确
logger.debug("用户: " + name + ", ID: " + id); // 错误
// 2. 完整异常信息
try {
// 业务代码
} catch (Exception e) {
logger.error("业务操作失败", e); // 正确 - 打印完整堆栈
// logger.error("业务操作失败: {}", e.getMessage()); // 错误 - 丢失堆栈
}
// 3. 避免记录敏感信息
// 不要: logger.info("用户密码: {}", password);
// 4. 使用debug级别记录调试信息
logger.debug("进入方法,参数: {}", requestParams);
// 5. 日志级别选择
// TRACE: 详细调试信息
// DEBUG: 调试信息
// INFO: 关键业务信息
// WARN: 可恢复的问题
// ERROR: 异常错误
}
}
日志框架性能对比
| 框架 | 特性 | 同步性能 | 异步性能 | 适用场景 |
|---|---|---|---|---|
| Logback | 实现简单,功能完善 | 中小型项目 | ||
| Log4j2 | 强大的过滤和路由 | 大型系统 | ||
| Java Util Logging | JDK自带 | 简单应用 |
常见问题解决
// 1. 避免日志框架冲突
// 排除冲突依赖
<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>
// 2. 循环依赖问题
// 在logback.xml中配置
<configuration>
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
</configuration>
这个案例涵盖了Java日志框架的主要使用场景和实践技巧,根据项目需求选择合适的技术方案,并遵循最佳实践来保证日志系统的健壮性和可用性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播