统一日志怎么做
在不少 Spring Boot 项目里,统一异常已经成了“标配”。 但真正把项目做大的团队,会把 统一日志体系 放在更重要的位置。
日志不是打印一下 log.info 那么简单。 日志是:
-
排查线上 Bug 的唯一线索
-
追踪链路的关键依据
-
数据分析的重要来源
-
监控告警的触发源
-
规范化团队工程能力的基石
-
项目越大,日志越是“生命线”。
这篇文章,我们就把 企业级日志体系 从理念到设计再到落地,一次讲透。 让你做项目不再凭感觉乱打 log。

1 日志为什么容易乱?(普通项目 vs 企业项目)
很多项目的日志体系,都是长这样的:
开发者写多了就变成:
-
看日志看不懂
-
线上问题复现不出来
-
同一个接口的调用链断裂
-
大量 debug 信息上了生产
-
想查某个请求,要翻几十 MB 日志
为什么?
因为缺少 统一规范 + 全链路日志设计 。
企业级项目的做法通常有三层:
-
日志规范(规则)
-
日志中间件(统一格式化)
-
日志链路(TraceId)
这篇文章就按照这三部分逐层展开,帮你搭出可复用的企业级模板。
2 企业项目的日志到底要统一哪些?(范围很大)
一套合格的日志体系,需要至少覆盖:
-
日志格式 (统一字段)
-
日志等级 (INFO/WARN/ERROR 的边界)
-
日志位置 (在哪里打,在哪里禁止打)
-
请求日志 (完整记录一次请求)
-
响应日志 (统一输出 & 脱敏)
-
异常日志 (归一化输出)
-
链路追踪 TraceId
-
慢接口监控
-
方法级别日志 AOP
-
敏感信息脱敏处理
-
生产日志滚动
-
审计日志 Audit Log
对,你没看错,日志体系巨大。 但我们今天把它讲得足够简单,并且给你直接能复制到项目里的代码。
3 统一日志体系的设计蓝图
先来看大局观:
你会发现:
-
每一层都会产生日志
-
但每一层输出的内容必须统一管理
-
最终让一个请求成为“可完整复盘的链路”
接下来我们逐步拆开讲。
4 从零到落地:企业级日志体系构建
1. 统一日志格式(Logging Format)—— (全项目同一种格式)
统一格式非常关键,因为没有标准格式,后续 ELK、OpenSearch、语义分析都没法做。
推荐格式(JSON 是最好解析的格式):
{
"timestamp": "2025-01-15 10:20:33.123",
"traceId": "b2d7e8f1...",
"level": "INFO",
"thread": "http-nio-8080-exec-2",
"class": "com.demo.UserController",
"message": "create user success",
"cost":12,
"params": {...},
"result": {...}
}
Spring Boot 使用 Logback 非常容易实现:
logback-spring.xml :
appender name="console"class="ch.qos.logback.core.ConsoleAppender">
encoderclass="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
providers>timestamp/>pattern>pattern>"traceId": "%X{traceId}",
"level": "%level",
"thread": "%thread",
"class": "%logger{36}",
"msg": "%message"
pattern>pattern>providers>encoder>appender>
关键点: traceId 通过 MDC 传递 —— 稍后会讲。
本文由“壹伴编辑器”提供技术支持
2. 接口请求日志(Request Logging)
企业项目一般要做到:
-
记录 URL
-
记录请求参数
-
记录请求耗时
-
自动关联 TraceId
-
可脱敏
最常见的方式:写一个 日志过滤器(Filter) 。
@Slf4j
@Component
public class RequestLogFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
long start = System.currentTimeMillis;
String traceId = UUID.randomUUID.toString.replace("-", "");
MDC.put("traceId", traceId);
log.info("REQUEST [{}] {} {}", req.getMethod, req.getRequestURI, buildParams(req));
chain.doFilter(req, res);long cost = System.currentTimeMillis - start;
log.info("RESPONSE [{}ms] {}", cost, traceId);
MDC.clear;}}
本文由“壹伴编辑器”提供技术支持
3. 响应日志统一封装(配合统一返回值 Result)
在统一返回值中加入日志钩子。
例如你的 GlobalResponseAdvice :
@Slf4j
@RestControllerAdvice
public class ResponseWrapper implements ResponseBodyAdviceObject> {
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType contentType,Class converterType,ServerHttpRequest req, ServerHttpResponse res){
log.info("RESPONSE BODY: {}", JsonUtils.toJson(body));
return body;
}
}
这样每个响应都会自动日志化。
本文由“壹伴编辑器”提供技术支持
4. 统一异常日志(配合统一异常处理器)
你之前已经做过统一异常,但核心补一条:
所有异常必须记录 traceId + errorCode + message + stack
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BizException.class)
public Result> handleBizException(BizException e) {
log.error("BizException: code={}, msg={}, traceId={}",
e.getCode, e.getMsg, MDC.get("traceId"), e);
return Result.error(e.getCode, e.getMsg);
}@ExceptionHandler(Exception.class)
public Result> handleOther(Exception e) {
log.error("UnhandledException: traceId={}", MDC.get("traceId"), e);
return Result.error(ErrorCode.SERVER_ERROR);
}}
做到这里, 异常链路完整可追踪 。
本文由“壹伴编辑器”提供技术支持
5. TraceId 全链路日志(MDC)核心机制
所有日志都要带上 traceId,否则无法串联。
关键点:
-
请求进入 Filter → 生成 traceId → 写入 MDC
-
后续所有日志自动带 traceId
-
响应结束时清除 MDC
-
异步线程必须手动传递 MDC(难点)
异步线程 MDC 传递方式:
public class MdcTaskWrapper implements Runnable {
private final Runnable task;
private final Map
public MdcTaskWrapper(Runnable task) {
this.task = task;
this.context = MDC.getCopyOfContextMap;
}@Override
public void run {
if (context != ) MDC.setContextMap(context);
try {
task.run;} finally {
MDC.clear;}}}
生产项目必须加这一层。
本文由“壹伴编辑器”提供技术支持
6. 方法级日志 AOP(记录耗时、参数、结果)
大量企业项目都会用 AOP 做方法级日志。
例如:
@Around("@annotation(Loggable)")
public Object logMethod(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis;
log.info("Method Start: {} args={}", pjp.getSignature, Arrays.toString(pjp.getArgs));
Object result = pjp.proceed;long cost = System.currentTimeMillis - start;
log.info("Method End: {} cost={}ms result={}", pjp.getSignature, cost, JsonUtils.toJson(result));
return result;
}
结合 注解 @Loggable 使用。
你可以让 Service/Manager 关键方法自动记录:
-
入参
-
出参
-
耗时
非常适合大型项目。
本文由“壹伴编辑器”提供技术支持
7. 慢接口分析(性能监控的重要来源)
关键思路:
-
接口耗时 > 500ms → WARN
-
耗时 > 2000ms → ERROR
代码示例:
if (cost > 2000) {
log.error("Slow API: {} cost={}ms", uri, cost);
} else if (cost >500) {
log.warn("Slow API: {} cost={}ms", uri, cost);
}
这是定位性能问题的核心指标。
本文由“壹伴编辑器”提供技术支持
8. 日志脱敏(尤其是手机号、身份证、地址)
不要把敏感数据打印到生产日志!
使用工具类自动脱敏:
public class MaskUtils {
public static String mobile(String s) {
return s.replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
}public static String idCard(String s) {
return s.replaceAll("(\\w{4})\\w*(\\w{4})", "$1****$2");
}}
然后在日志切面里调用:
String safeParams = MaskUtils.mask(JsonUtils.toJson(args));
本文由“壹伴编辑器”提供技术支持
9. 生产日志滚动策略(避免日志撑爆磁盘)
logback-spring.xml :
rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
fileNamePattern>logs/app.%d{yyyy-MM-dd}.log.gzfileNamePattern>
maxHistory>30maxHistory>
totalSizeCap>2GBtotalSizeCap>
rollingPolicy>
保证日志合理分片、压缩、清理。
本文由“壹伴编辑器”提供技术支持
10. 审计日志(Audit Log)
适用于:
-
后台管理系统
-
用户权限操作
-
金融相关
-
重要数据修改
设计方式较简单:
@Slf4j
public void recordAudit(String operator, String action, Object data) {
log.info("[AUDIT] operator={} action={} data={}",
operator, action, JsonUtils.toJson(data));
}
企业项目几乎都会有这一块。
5 全链路示例:一次请求如何被日志完整追踪?
假设用户调用:
POST /user/create
日志链路会像这样:
RequestLogFilter:
REQUEST POST /user/create params={...}, traceId=xxx
AOP:
Method Start:UserService.create args=[...]
Repository:
SQL:insert into user...
AOP:
Method End:cost=10ms result={id: 1 }
ResponseAdvice:
RESPONSE BODY:{code: 0 ,data:{id: 1 }}
最终输出:RESPONSE [15ms] traceId=xxx
开发者只需要一个 traceId 就能追完所有链路。

总结
当你把统一日志体系落地之后,你会明显感受到:
-
排查问题速度成倍提升
-
团队开发一致性变更强
-
异常链路一目了然
-
性能问题易复现
-
业务变化更可控
-
整个项目可观测性跃升一个层级
日志不是“系统附属品”。 日志是你与系统沟通的唯一语言。 而统一日志体系,是这套语言的语法、句法和风格指南。

浙公网安备 33010602011771号