第241集SpringBoot AOP请求链路日志架构实战:统一日志打印、链路追踪、性能监控的企业级解决方案

前言

在复杂的微服务架构中,请求链路日志的统一管理和追踪是系统可观测性的核心要素。传统的日志记录方式分散在各个业务模块中,缺乏统一的规范和链路追踪能力,导致问题排查困难、性能分析复杂。基于SpringBoot的AOP请求链路日志架构,不仅能够实现统一的日志打印,还能提供完整的链路追踪、性能监控和异常分析能力。随着微服务架构和分布式系统的普及,构建可观测、可追踪的日志体系,已成为企业级架构师必须掌握的核心技能。

本文将深入探讨SpringBoot中AOP请求链路日志的架构设计与实战应用,从统一日志打印到链路追踪,从性能监控到异常分析,为企业构建稳定、高效的请求链路日志解决方案提供全面的技术指导。

一、SpringBoot AOP请求链路日志架构概述与核心原理

1.1 AOP请求链路日志架构设计

SpringBoot AOP请求链路日志系统采用分层架构设计,通过统一日志打印、链路追踪、性能监控等技术,实现高效的请求链路管理能力。

1.2 核心组件架构

二、企业级AOP请求链路日志管理器设计

2.1 AOP切面核心管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/**
* 企业级AOP请求链路日志管理器
* 提供统一的请求链路日志打印和追踪能力
*/
@Aspect
@Component
@Slf4j
public class RequestLogAspect {

private final LogManager logManager;
private final TraceManager traceManager;
private final PerformanceMonitor performanceMonitor;
private final ExceptionAnalyzer exceptionAnalyzer;

private final ThreadLocal<RequestLogContext> requestLogContext = new ThreadLocal<>();

/**
* 拦截Controller方法
*/
@Around("@annotation(org.springframework.web.bind.annotation.RequestMapping) || " +
"@annotation(org.springframework.web.bind.annotation.GetMapping) || " +
"@annotation(org.springframework.web.bind.annotation.PostMapping) || " +
"@annotation(org.springframework.web.bind.annotation.PutMapping) || " +
"@annotation(org.springframework.web.bind.annotation.DeleteMapping)")
public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {
return processRequest(joinPoint, "CONTROLLER");
}

/**
* 拦截Service方法
*/
@Around("@annotation(org.springframework.stereotype.Service)")
public Object aroundService(ProceedingJoinPoint joinPoint) throws Throwable {
return processRequest(joinPoint, "SERVICE");
}

/**
* 拦截Repository方法
*/
@Around("@annotation(org.springframework.stereotype.Repository)")
public Object aroundRepository(ProceedingJoinPoint joinPoint) throws Throwable {
return processRequest(joinPoint, "REPOSITORY");
}

/**
* 拦截自定义注解方法
*/
@Around("@annotation(com.company.log.annotation.RequestLog)")
public Object aroundRequestLog(ProceedingJoinPoint joinPoint) throws Throwable {
RequestLog requestLogAnnotation = getRequestLogAnnotation(joinPoint);
return processRequest(joinPoint, requestLogAnnotation.value());
}

/**
* 处理请求
*/
private Object processRequest(ProceedingJoinPoint joinPoint, String layer) throws Throwable {
long startTime = System.currentTimeMillis();
String traceId = null;
String spanId = null;

try {
// 1. 创建请求日志上下文
RequestLogContext context = createRequestLogContext(joinPoint, layer);
requestLogContext.set(context);

// 2. 生成链路追踪信息
traceId = traceManager.generateTraceId();
spanId = traceManager.generateSpanId();

// 3. 设置链路上下文
traceManager.setTraceContext(traceId, spanId, context);

// 4. 记录请求开始日志
logManager.logRequestStart(context, traceId, spanId);

// 5. 性能监控开始
performanceMonitor.startMonitoring(context);

// 6. 执行目标方法
Object result = joinPoint.proceed();

// 7. 计算执行时间
long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime;

// 8. 更新上下文
context.setExecutionTime(executionTime);
context.setResult(result);
context.setSuccess(true);

// 9. 记录请求成功日志
logManager.logRequestSuccess(context, traceId, spanId);

// 10. 性能监控结束
performanceMonitor.endMonitoring(context, true);

return result;

} catch (Exception e) {
// 异常处理
long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime;

RequestLogContext context = requestLogContext.get();
if (context != null) {
context.setExecutionTime(executionTime);
context.setException(e);
context.setSuccess(false);

// 记录请求异常日志
logManager.logRequestError(context, traceId, spanId);

// 异常分析
exceptionAnalyzer.analyzeException(context, e);

// 性能监控结束
performanceMonitor.endMonitoring(context, false);
}

throw e;

} finally {
// 清理资源
cleanup();
}
}

/**
* 创建请求日志上下文
*/
private RequestLogContext createRequestLogContext(ProceedingJoinPoint joinPoint, String layer) {
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Object target = joinPoint.getTarget();
Object[] args = joinPoint.getArgs();

// 获取HTTP请求信息
HttpServletRequest request = getHttpServletRequest();

RequestLogContext context = RequestLogContext.builder()
.layer(layer)
.className(target.getClass().getSimpleName())
.methodName(method.getName())
.methodSignature(signature.toString())
.arguments(args)
.startTime(System.currentTimeMillis())
.threadId(Thread.currentThread().getId())
.threadName(Thread.currentThread().getName())
.build();

// 设置HTTP请求信息
if (request != null) {
context.setRequestUrl(request.getRequestURL().toString());
context.setRequestMethod(request.getMethod());
context.setClientIp(getClientIp(request));
context.setUserAgent(request.getHeader("User-Agent"));
context.setRequestHeaders(getRequestHeaders(request));
context.setRequestParams(getRequestParams(request));
}

return context;

} catch (Exception e) {
log.error("创建请求日志上下文失败", e);
throw new RequestLogException("创建请求日志上下文失败: " + e.getMessage());
}
}

/**
* 获取HTTP请求
*/
private HttpServletRequest getHttpServletRequest() {
try {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
return ((ServletRequestAttributes) requestAttributes).getRequest();
}
} catch (Exception e) {
log.debug("获取HTTP请求失败: {}", e.getMessage());
}
return null;
}

/**
* 获取客户端IP
*/
private String getClientIp(HttpServletRequest request) {
try {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
} catch (Exception e) {
log.debug("获取客户端IP失败: {}", e.getMessage());
return "unknown";
}
}

/**
* 获取请求头
*/
private Map<String, String> getRequestHeaders(HttpServletRequest request) {
try {
Map<String, String> headers = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
headers.put(headerName, headerValue);
}
return headers;
} catch (Exception e) {
log.debug("获取请求头失败: {}", e.getMessage());
return new HashMap<>();
}
}

/**
* 获取请求参数
*/
private Map<String, Object> getRequestParams(HttpServletRequest request) {
try {
Map<String, Object> params = new HashMap<>();
Map<String, String[]> parameterMap = request.getParameterMap();
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
String key = entry.getKey();
String[] values = entry.getValue();
if (values.length == 1) {
params.put(key, values[0]);
} else {
params.put(key, Arrays.asList(values));
}
}
return params;
} catch (Exception e) {
log.debug("获取请求参数失败: {}", e.getMessage());
return new HashMap<>();
}
}

/**
* 获取RequestLog注解
*/
private RequestLog getRequestLogAnnotation(ProceedingJoinPoint joinPoint) {
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
return method.getAnnotation(RequestLog.class);
} catch (Exception e) {
log.debug("获取RequestLog注解失败: {}", e.getMessage());
return null;
}
}

/**
* 清理资源
*/
private void cleanup() {
try {
requestLogContext.remove();
traceManager.clearTraceContext();
} catch (Exception e) {
log.error("清理资源失败", e);
}
}
}

2.2 日志管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/**
* 日志管理器
* 负责统一管理各种类型的日志
*/
@Component
@Slf4j
public class LogManager {

private final LogProcessor requestLogProcessor;
private final LogProcessor responseLogProcessor;
private final LogProcessor businessLogProcessor;
private final LogProcessor exceptionLogProcessor;

private final LogFormatter logFormatter;
private final LogOutputter logOutputter;

/**
* 记录请求开始日志
*/
public void logRequestStart(RequestLogContext context, String traceId, String spanId) {
try {
RequestLogInfo logInfo = RequestLogInfo.builder()
.traceId(traceId)
.spanId(spanId)
.layer(context.getLayer())
.className(context.getClassName())
.methodName(context.getMethodName())
.requestUrl(context.getRequestUrl())
.requestMethod(context.getRequestMethod())
.clientIp(context.getClientIp())
.userAgent(context.getUserAgent())
.requestHeaders(context.getRequestHeaders())
.requestParams(context.getRequestParams())
.arguments(context.getArguments())
.startTime(context.getStartTime())
.threadId(context.getThreadId())
.threadName(context.getThreadName())
.logType(LogType.REQUEST_START)
.build();

// 处理日志
requestLogProcessor.process(logInfo);

// 格式化日志
String formattedLog = logFormatter.format(logInfo);

// 输出日志
logOutputter.output(formattedLog, LogLevel.INFO);

log.debug("请求开始日志记录成功: {} - {}", traceId, spanId);

} catch (Exception e) {
log.error("记录请求开始日志失败", e);
}
}

/**
* 记录请求成功日志
*/
public void logRequestSuccess(RequestLogContext context, String traceId, String spanId) {
try {
ResponseLogInfo logInfo = ResponseLogInfo.builder()
.traceId(traceId)
.spanId(spanId)
.layer(context.getLayer())
.className(context.getClassName())
.methodName(context.getMethodName())
.requestUrl(context.getRequestUrl())
.requestMethod(context.getRequestMethod())
.clientIp(context.getClientIp())
.result(context.getResult())
.executionTime(context.getExecutionTime())
.startTime(context.getStartTime())
.endTime(System.currentTimeMillis())
.threadId(context.getThreadId())
.threadName(context.getThreadName())
.logType(LogType.REQUEST_SUCCESS)
.build();

// 处理日志
responseLogProcessor.process(logInfo);

// 格式化日志
String formattedLog = logFormatter.format(logInfo);

// 输出日志
logOutputter.output(formattedLog, LogLevel.INFO);

log.debug("请求成功日志记录成功: {} - {}", traceId, spanId);

} catch (Exception e) {
log.error("记录请求成功日志失败", e);
}
}

/**
* 记录请求异常日志
*/
public void logRequestError(RequestLogContext context, String traceId, String spanId) {
try {
ExceptionLogInfo logInfo = ExceptionLogInfo.builder()
.traceId(traceId)
.spanId(spanId)
.layer(context.getLayer())
.className(context.getClassName())
.methodName(context.getMethodName())
.requestUrl(context.getRequestUrl())
.requestMethod(context.getRequestMethod())
.clientIp(context.getClientIp())
.exception(context.getException())
.executionTime(context.getExecutionTime())
.startTime(context.getStartTime())
.endTime(System.currentTimeMillis())
.threadId(context.getThreadId())
.threadName(context.getThreadName())
.logType(LogType.REQUEST_ERROR)
.build();

// 处理日志
exceptionLogProcessor.process(logInfo);

// 格式化日志
String formattedLog = logFormatter.format(logInfo);

// 输出日志
logOutputter.output(formattedLog, LogLevel.ERROR);

log.debug("请求异常日志记录成功: {} - {}", traceId, spanId);

} catch (Exception e) {
log.error("记录请求异常日志失败", e);
}
}

/**
* 记录业务日志
*/
public void logBusiness(String traceId, String spanId, String businessType, Object businessData) {
try {
BusinessLogInfo logInfo = BusinessLogInfo.builder()
.traceId(traceId)
.spanId(spanId)
.businessType(businessType)
.businessData(businessData)
.timestamp(System.currentTimeMillis())
.threadId(Thread.currentThread().getId())
.threadName(Thread.currentThread().getName())
.logType(LogType.BUSINESS)
.build();

// 处理日志
businessLogProcessor.process(logInfo);

// 格式化日志
String formattedLog = logFormatter.format(logInfo);

// 输出日志
logOutputter.output(formattedLog, LogLevel.INFO);

log.debug("业务日志记录成功: {} - {}", traceId, spanId);

} catch (Exception e) {
log.error("记录业务日志失败", e);
}
}

/**
* 记录性能日志
*/
public void logPerformance(String traceId, String spanId, PerformanceMetrics metrics) {
try {
PerformanceLogInfo logInfo = PerformanceLogInfo.builder()
.traceId(traceId)
.spanId(spanId)
.metrics(metrics)
.timestamp(System.currentTimeMillis())
.threadId(Thread.currentThread().getId())
.threadName(Thread.currentThread().getName())
.logType(LogType.PERFORMANCE)
.build();

// 格式化日志
String formattedLog = logFormatter.format(logInfo);

// 输出日志
logOutputter.output(formattedLog, LogLevel.INFO);

log.debug("性能日志记录成功: {} - {}", traceId, spanId);

} catch (Exception e) {
log.error("记录性能日志失败", e);
}
}
}

2.3 链路追踪管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/**
* 链路追踪管理器
* 负责管理请求链路追踪信息
*/
@Component
@Slf4j
public class TraceManager {

private final TraceIdGenerator traceIdGenerator;
private final SpanManager spanManager;
private final ThreadLocal<TraceContext> traceContext = new ThreadLocal<>();

/**
* 生成TraceId
*/
public String generateTraceId() {
try {
String traceId = traceIdGenerator.generate();
log.debug("生成TraceId: {}", traceId);
return traceId;
} catch (Exception e) {
log.error("生成TraceId失败", e);
return UUID.randomUUID().toString().replace("-", "");
}
}

/**
* 生成SpanId
*/
public String generateSpanId() {
try {
String spanId = spanManager.generateSpanId();
log.debug("生成SpanId: {}", spanId);
return spanId;
} catch (Exception e) {
log.error("生成SpanId失败", e);
return UUID.randomUUID().toString().replace("-", "");
}
}

/**
* 设置链路上下文
*/
public void setTraceContext(String traceId, String spanId, RequestLogContext requestContext) {
try {
TraceContext context = TraceContext.builder()
.traceId(traceId)
.spanId(spanId)
.parentSpanId(getParentSpanId())
.requestContext(requestContext)
.startTime(System.currentTimeMillis())
.build();

traceContext.set(context);

// 设置到MDC
MDC.put("traceId", traceId);
MDC.put("spanId", spanId);

log.debug("设置链路上下文成功: {} - {}", traceId, spanId);

} catch (Exception e) {
log.error("设置链路上下文失败", e);
}
}

/**
* 获取当前链路上下文
*/
public TraceContext getCurrentTraceContext() {
return traceContext.get();
}

/**
* 获取当前TraceId
*/
public String getCurrentTraceId() {
TraceContext context = traceContext.get();
return context != null ? context.getTraceId() : null;
}

/**
* 获取当前SpanId
*/
public String getCurrentSpanId() {
TraceContext context = traceContext.get();
return context != null ? context.getSpanId() : null;
}

/**
* 获取父SpanId
*/
private String getParentSpanId() {
try {
// 从HTTP请求头中获取父SpanId
HttpServletRequest request = getHttpServletRequest();
if (request != null) {
String parentSpanId = request.getHeader("X-Parent-Span-Id");
if (parentSpanId != null && !parentSpanId.isEmpty()) {
return parentSpanId;
}
}

// 从当前链路上下文中获取
TraceContext currentContext = traceContext.get();
if (currentContext != null) {
return currentContext.getSpanId();
}

return null;

} catch (Exception e) {
log.debug("获取父SpanId失败: {}", e.getMessage());
return null;
}
}

/**
* 获取HTTP请求
*/
private HttpServletRequest getHttpServletRequest() {
try {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
return ((ServletRequestAttributes) requestAttributes).getRequest();
}
} catch (Exception e) {
log.debug("获取HTTP请求失败: {}", e.getMessage());
}
return null;
}

/**
* 清理链路上下文
*/
public void clearTraceContext() {
try {
traceContext.remove();
MDC.remove("traceId");
MDC.remove("spanId");

log.debug("清理链路上下文成功");

} catch (Exception e) {
log.error("清理链路上下文失败", e);
}
}

/**
* 创建子Span
*/
public String createChildSpan(String operationName) {
try {
TraceContext parentContext = traceContext.get();
if (parentContext == null) {
log.warn("无法创建子Span,父链路上下文不存在");
return null;
}

String childSpanId = generateSpanId();

TraceContext childContext = TraceContext.builder()
.traceId(parentContext.getTraceId())
.spanId(childSpanId)
.parentSpanId(parentContext.getSpanId())
.operationName(operationName)
.startTime(System.currentTimeMillis())
.build();

traceContext.set(childContext);

// 更新MDC
MDC.put("spanId", childSpanId);

log.debug("创建子Span成功: {} - {}", parentContext.getTraceId(), childSpanId);
return childSpanId;

} catch (Exception e) {
log.error("创建子Span失败", e);
return null;
}
}

/**
* 完成Span
*/
public void finishSpan() {
try {
TraceContext context = traceContext.get();
if (context == null) {
log.warn("无法完成Span,链路上下文不存在");
return;
}

context.setEndTime(System.currentTimeMillis());
context.setDuration(context.getEndTime() - context.getStartTime());

// 记录Span信息
spanManager.recordSpan(context);

log.debug("完成Span成功: {} - {}", context.getTraceId(), context.getSpanId());

} catch (Exception e) {
log.error("完成Span失败", e);
}
}
}

三、性能监控与异常分析

3.1 性能监控器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
* 性能监控器
* 负责监控请求性能指标
*/
@Component
@Slf4j
public class PerformanceMonitor {

private final Map<String, PerformanceMetrics> metricsMap = new ConcurrentHashMap<>();
private final AtomicLong totalRequests = new AtomicLong(0);
private final AtomicLong totalExecutionTime = new AtomicLong(0);

private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

/**
* 开始性能监控
*/
public void startMonitoring(RequestLogContext context) {
try {
String key = generateKey(context);

PerformanceMetrics metrics = metricsMap.computeIfAbsent(key, k ->
PerformanceMetrics.builder()
.key(k)
.className(context.getClassName())
.methodName(context.getMethodName())
.layer(context.getLayer())
.requestCount(0)
.totalExecutionTime(0)
.averageExecutionTime(0)
.maxExecutionTime(0)
.minExecutionTime(Long.MAX_VALUE)
.successCount(0)
.errorCount(0)
.lastExecutionTime(0)
.build()
);

metrics.setLastExecutionTime(System.currentTimeMillis());

log.debug("开始性能监控: {}", key);

} catch (Exception e) {
log.error("开始性能监控失败", e);
}
}

/**
* 结束性能监控
*/
public void endMonitoring(RequestLogContext context, boolean success) {
try {
String key = generateKey(context);
PerformanceMetrics metrics = metricsMap.get(key);

if (metrics != null) {
long executionTime = context.getExecutionTime();

// 更新指标
metrics.setRequestCount(metrics.getRequestCount() + 1);
metrics.setTotalExecutionTime(metrics.getTotalExecutionTime() + executionTime);
metrics.setAverageExecutionTime(metrics.getTotalExecutionTime() / metrics.getRequestCount());
metrics.setMaxExecutionTime(Math.max(metrics.getMaxExecutionTime(), executionTime));
metrics.setMinExecutionTime(Math.min(metrics.getMinExecutionTime(), executionTime));

if (success) {
metrics.setSuccessCount(metrics.getSuccessCount() + 1);
} else {
metrics.setErrorCount(metrics.getErrorCount() + 1);
}

// 更新全局指标
totalRequests.incrementAndGet();
totalExecutionTime.addAndGet(executionTime);

log.debug("结束性能监控: {} - 执行时间: {}ms", key, executionTime);
}

} catch (Exception e) {
log.error("结束性能监控失败", e);
}
}

/**
* 生成监控键
*/
private String generateKey(RequestLogContext context) {
return context.getLayer() + ":" + context.getClassName() + "." + context.getMethodName();
}

/**
* 获取性能指标
*/
public Map<String, PerformanceMetrics> getMetrics() {
return new HashMap<>(metricsMap);
}

/**
* 获取总体性能指标
*/
public OverallPerformanceMetrics getOverallMetrics() {
try {
long total = totalRequests.get();
long totalTime = totalExecutionTime.get();
double averageTime = total > 0 ? (double) totalTime / total : 0;

return OverallPerformanceMetrics.builder()
.totalRequests(total)
.totalExecutionTime(totalTime)
.averageExecutionTime(averageTime)
.monitoredMethodsCount(metricsMap.size())
.build();

} catch (Exception e) {
log.error("获取总体性能指标失败", e);
throw new PerformanceException("获取总体性能指标失败: " + e.getMessage());
}
}

/**
* 启动性能监控
*/
@PostConstruct
public void startMonitoring() {
scheduler.scheduleAtFixedRate(() -> {
try {
logPerformanceMetrics();
} catch (Exception e) {
log.error("性能监控失败", e);
}
}, 0, 60, TimeUnit.SECONDS);
}

/**
* 记录性能指标
*/
private void logPerformanceMetrics() {
try {
OverallPerformanceMetrics overallMetrics = getOverallMetrics();

log.info("性能监控指标 - 总请求数: {}, 总执行时间: {}ms, 平均执行时间: {}ms, 监控方法数: {}",
overallMetrics.getTotalRequests(),
overallMetrics.getTotalExecutionTime(),
overallMetrics.getAverageExecutionTime(),
overallMetrics.getMonitoredMethodsCount());

// 记录每个方法的性能指标
for (PerformanceMetrics metrics : metricsMap.values()) {
log.debug("方法性能指标 - {}: 请求数={}, 平均执行时间={}ms, 最大执行时间={}ms, 最小执行时间={}ms, 成功率={}%",
metrics.getKey(),
metrics.getRequestCount(),
metrics.getAverageExecutionTime(),
metrics.getMaxExecutionTime(),
metrics.getMinExecutionTime(),
metrics.getRequestCount() > 0 ? (double) metrics.getSuccessCount() / metrics.getRequestCount() * 100 : 0);
}

} catch (Exception e) {
log.error("记录性能指标失败", e);
}
}

/**
* 清理性能监控器
*/
@PreDestroy
public void cleanup() {
try {
scheduler.shutdown();
metricsMap.clear();

log.info("性能监控器清理完成");

} catch (Exception e) {
log.error("性能监控器清理失败", e);
}
}
}

3.2 异常分析器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/**
* 异常分析器
* 负责分析和处理异常信息
*/
@Component
@Slf4j
public class ExceptionAnalyzer {

private final Map<String, ExceptionInfo> exceptionMap = new ConcurrentHashMap<>();
private final AtomicLong totalExceptions = new AtomicLong(0);
private final AtomicLong totalErrors = new AtomicLong(0);

private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

/**
* 分析异常
*/
public void analyzeException(RequestLogContext context, Exception exception) {
try {
totalExceptions.incrementAndGet();

String exceptionKey = generateExceptionKey(exception);
ExceptionInfo exceptionInfo = exceptionMap.computeIfAbsent(exceptionKey, k ->
ExceptionInfo.builder()
.exceptionKey(k)
.exceptionType(exception.getClass().getSimpleName())
.exceptionMessage(exception.getMessage())
.occurrenceCount(0)
.firstOccurrenceTime(System.currentTimeMillis())
.lastOccurrenceTime(System.currentTimeMillis())
.affectedMethods(new HashSet<>())
.affectedLayers(new HashSet<>())
.build()
);

// 更新异常信息
exceptionInfo.setOccurrenceCount(exceptionInfo.getOccurrenceCount() + 1);
exceptionInfo.setLastOccurrenceTime(System.currentTimeMillis());
exceptionInfo.getAffectedMethods().add(context.getClassName() + "." + context.getMethodName());
exceptionInfo.getAffectedLayers().add(context.getLayer());

// 记录异常详情
ExceptionDetail detail = ExceptionDetail.builder()
.traceId(context.getTraceId())
.spanId(context.getSpanId())
.layer(context.getLayer())
.className(context.getClassName())
.methodName(context.getMethodName())
.requestUrl(context.getRequestUrl())
.requestMethod(context.getRequestMethod())
.clientIp(context.getClientIp())
.exception(exception)
.stackTrace(getStackTrace(exception))
.executionTime(context.getExecutionTime())
.timestamp(System.currentTimeMillis())
.build();

// 存储异常详情
storeExceptionDetail(detail);

// 检查是否需要告警
checkExceptionAlert(exceptionInfo);

log.debug("异常分析完成: {} - {}", exceptionKey, exception.getMessage());

} catch (Exception e) {
log.error("异常分析失败", e);
}
}

/**
* 生成异常键
*/
private String generateExceptionKey(Exception exception) {
return exception.getClass().getSimpleName() + ":" + exception.getMessage();
}

/**
* 获取堆栈跟踪
*/
private String getStackTrace(Exception exception) {
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
exception.printStackTrace(pw);
return sw.toString();
} catch (Exception e) {
log.debug("获取堆栈跟踪失败: {}", e.getMessage());
return "无法获取堆栈跟踪";
}
}

/**
* 存储异常详情
*/
private void storeExceptionDetail(ExceptionDetail detail) {
try {
// 这里可以将异常详情存储到数据库或文件系统
// 简化实现,记录到日志
log.error("异常详情 - TraceId: {}, SpanId: {}, 方法: {}.{}, 异常: {}",
detail.getTraceId(),
detail.getSpanId(),
detail.getClassName(),
detail.getMethodName(),
detail.getException().getMessage());

} catch (Exception e) {
log.error("存储异常详情失败", e);
}
}

/**
* 检查异常告警
*/
private void checkExceptionAlert(ExceptionInfo exceptionInfo) {
try {
// 检查异常频率
if (exceptionInfo.getOccurrenceCount() > 10) {
log.warn("异常频率过高: {} - 发生次数: {}",
exceptionInfo.getExceptionKey(),
exceptionInfo.getOccurrenceCount());
}

// 检查异常类型
if (exceptionInfo.getExceptionType().contains("OutOfMemoryError")) {
log.error("内存溢出异常: {}", exceptionInfo.getExceptionKey());
}

// 检查异常影响范围
if (exceptionInfo.getAffectedLayers().size() > 3) {
log.warn("异常影响范围过大: {} - 影响层级: {}",
exceptionInfo.getExceptionKey(),
exceptionInfo.getAffectedLayers());
}

} catch (Exception e) {
log.error("检查异常告警失败", e);
}
}

/**
* 获取异常统计
*/
public ExceptionStatistics getExceptionStatistics() {
try {
return ExceptionStatistics.builder()
.totalExceptions(totalExceptions.get())
.totalErrors(totalErrors.get())
.exceptionTypesCount(exceptionMap.size())
.exceptionInfos(new ArrayList<>(exceptionMap.values()))
.build();

} catch (Exception e) {
log.error("获取异常统计失败", e);
throw new ExceptionAnalysisException("获取异常统计失败: " + e.getMessage());
}
}

/**
* 启动异常分析
*/
@PostConstruct
public void startAnalysis() {
scheduler.scheduleAtFixedRate(() -> {
try {
logExceptionStatistics();
} catch (Exception e) {
log.error("异常分析失败", e);
}
}, 0, 300, TimeUnit.SECONDS); // 每5分钟分析一次
}

/**
* 记录异常统计
*/
private void logExceptionStatistics() {
try {
ExceptionStatistics statistics = getExceptionStatistics();

log.info("异常统计 - 总异常数: {}, 异常类型数: {}",
statistics.getTotalExceptions(),
statistics.getExceptionTypesCount());

// 记录异常详情
for (ExceptionInfo info : statistics.getExceptionInfos()) {
log.debug("异常信息 - {}: 发生次数={}, 影响方法数={}, 影响层级数={}",
info.getExceptionKey(),
info.getOccurrenceCount(),
info.getAffectedMethods().size(),
info.getAffectedLayers().size());
}

} catch (Exception e) {
log.error("记录异常统计失败", e);
}
}

/**
* 清理异常分析器
*/
@PreDestroy
public void cleanup() {
try {
scheduler.shutdown();
exceptionMap.clear();

log.info("异常分析器清理完成");

} catch (Exception e) {
log.error("异常分析器清理失败", e);
}
}
}

四、日志格式化与输出

4.1 日志格式化器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/**
* 日志格式化器
* 负责格式化各种类型的日志
*/
@Component
@Slf4j
public class LogFormatter {

private final ObjectMapper objectMapper;
private final LogFormatConfig formatConfig;

/**
* 格式化请求日志
*/
public String format(RequestLogInfo logInfo) {
try {
switch (formatConfig.getFormatType()) {
case JSON:
return formatAsJson(logInfo);
case TEXT:
return formatAsText(logInfo);
case STRUCTURED:
return formatAsStructured(logInfo);
default:
return formatAsJson(logInfo);
}
} catch (Exception e) {
log.error("格式化请求日志失败", e);
return "格式化失败: " + e.getMessage();
}
}

/**
* 格式化响应日志
*/
public String format(ResponseLogInfo logInfo) {
try {
switch (formatConfig.getFormatType()) {
case JSON:
return formatAsJson(logInfo);
case TEXT:
return formatAsText(logInfo);
case STRUCTURED:
return formatAsStructured(logInfo);
default:
return formatAsJson(logInfo);
}
} catch (Exception e) {
log.error("格式化响应日志失败", e);
return "格式化失败: " + e.getMessage();
}
}

/**
* 格式化异常日志
*/
public String format(ExceptionLogInfo logInfo) {
try {
switch (formatConfig.getFormatType()) {
case JSON:
return formatAsJson(logInfo);
case TEXT:
return formatAsText(logInfo);
case STRUCTURED:
return formatAsStructured(logInfo);
default:
return formatAsJson(logInfo);
}
} catch (Exception e) {
log.error("格式化异常日志失败", e);
return "格式化失败: " + e.getMessage();
}
}

/**
* 格式化业务日志
*/
public String format(BusinessLogInfo logInfo) {
try {
switch (formatConfig.getFormatType()) {
case JSON:
return formatAsJson(logInfo);
case TEXT:
return formatAsText(logInfo);
case STRUCTURED:
return formatAsStructured(logInfo);
default:
return formatAsJson(logInfo);
}
} catch (Exception e) {
log.error("格式化业务日志失败", e);
return "格式化失败: " + e.getMessage();
}
}

/**
* 格式化性能日志
*/
public String format(PerformanceLogInfo logInfo) {
try {
switch (formatConfig.getFormatType()) {
case JSON:
return formatAsJson(logInfo);
case TEXT:
return formatAsText(logInfo);
case STRUCTURED:
return formatAsStructured(logInfo);
default:
return formatAsJson(logInfo);
}
} catch (Exception e) {
log.error("格式化性能日志失败", e);
return "格式化失败: " + e.getMessage();
}
}

/**
* 格式化为JSON
*/
private String formatAsJson(Object logInfo) {
try {
return objectMapper.writeValueAsString(logInfo);
} catch (Exception e) {
log.error("JSON格式化失败", e);
return "JSON格式化失败: " + e.getMessage();
}
}

/**
* 格式化为文本
*/
private String formatAsText(Object logInfo) {
try {
if (logInfo instanceof RequestLogInfo) {
return formatRequestLogAsText((RequestLogInfo) logInfo);
} else if (logInfo instanceof ResponseLogInfo) {
return formatResponseLogAsText((ResponseLogInfo) logInfo);
} else if (logInfo instanceof ExceptionLogInfo) {
return formatExceptionLogAsText((ExceptionLogInfo) logInfo);
} else if (logInfo instanceof BusinessLogInfo) {
return formatBusinessLogAsText((BusinessLogInfo) logInfo);
} else if (logInfo instanceof PerformanceLogInfo) {
return formatPerformanceLogAsText((PerformanceLogInfo) logInfo);
}

return logInfo.toString();

} catch (Exception e) {
log.error("文本格式化失败", e);
return "文本格式化失败: " + e.getMessage();
}
}

/**
* 格式化为结构化文本
*/
private String formatAsStructured(Object logInfo) {
try {
StringBuilder sb = new StringBuilder();

if (logInfo instanceof RequestLogInfo) {
RequestLogInfo info = (RequestLogInfo) logInfo;
sb.append("[").append(info.getLogType()).append("] ");
sb.append("TraceId=").append(info.getTraceId()).append(" ");
sb.append("SpanId=").append(info.getSpanId()).append(" ");
sb.append("Layer=").append(info.getLayer()).append(" ");
sb.append("Method=").append(info.getClassName()).append(".").append(info.getMethodName()).append(" ");
sb.append("URL=").append(info.getRequestUrl()).append(" ");
sb.append("Method=").append(info.getRequestMethod()).append(" ");
sb.append("ClientIP=").append(info.getClientIp()).append(" ");
sb.append("StartTime=").append(new Date(info.getStartTime())).append(" ");
} else if (logInfo instanceof ResponseLogInfo) {
ResponseLogInfo info = (ResponseLogInfo) logInfo;
sb.append("[").append(info.getLogType()).append("] ");
sb.append("TraceId=").append(info.getTraceId()).append(" ");
sb.append("SpanId=").append(info.getSpanId()).append(" ");
sb.append("Layer=").append(info.getLayer()).append(" ");
sb.append("Method=").append(info.getClassName()).append(".").append(info.getMethodName()).append(" ");
sb.append("ExecutionTime=").append(info.getExecutionTime()).append("ms ");
sb.append("EndTime=").append(new Date(info.getEndTime())).append(" ");
} else if (logInfo instanceof ExceptionLogInfo) {
ExceptionLogInfo info = (ExceptionLogInfo) logInfo;
sb.append("[").append(info.getLogType()).append("] ");
sb.append("TraceId=").append(info.getTraceId()).append(" ");
sb.append("SpanId=").append(info.getSpanId()).append(" ");
sb.append("Layer=").append(info.getLayer()).append(" ");
sb.append("Method=").append(info.getClassName()).append(".").append(info.getMethodName()).append(" ");
sb.append("Exception=").append(info.getException().getClass().getSimpleName()).append(" ");
sb.append("Message=").append(info.getException().getMessage()).append(" ");
sb.append("ExecutionTime=").append(info.getExecutionTime()).append("ms ");
}

return sb.toString();

} catch (Exception e) {
log.error("结构化格式化失败", e);
return "结构化格式化失败: " + e.getMessage();
}
}

/**
* 格式化请求日志为文本
*/
private String formatRequestLogAsText(RequestLogInfo logInfo) {
StringBuilder sb = new StringBuilder();
sb.append("=== 请求开始 ===\n");
sb.append("TraceId: ").append(logInfo.getTraceId()).append("\n");
sb.append("SpanId: ").append(logInfo.getSpanId()).append("\n");
sb.append("Layer: ").append(logInfo.getLayer()).append("\n");
sb.append("Method: ").append(logInfo.getClassName()).append(".").append(logInfo.getMethodName()).append("\n");
sb.append("URL: ").append(logInfo.getRequestUrl()).append("\n");
sb.append("HTTP Method: ").append(logInfo.getRequestMethod()).append("\n");
sb.append("Client IP: ").append(logInfo.getClientIp()).append("\n");
sb.append("User Agent: ").append(logInfo.getUserAgent()).append("\n");
sb.append("Start Time: ").append(new Date(logInfo.getStartTime())).append("\n");
sb.append("Thread: ").append(logInfo.getThreadName()).append("\n");
sb.append("==================");
return sb.toString();
}

/**
* 格式化响应日志为文本
*/
private String formatResponseLogAsText(ResponseLogInfo logInfo) {
StringBuilder sb = new StringBuilder();
sb.append("=== 请求成功 ===\n");
sb.append("TraceId: ").append(logInfo.getTraceId()).append("\n");
sb.append("SpanId: ").append(logInfo.getSpanId()).append("\n");
sb.append("Layer: ").append(logInfo.getLayer()).append("\n");
sb.append("Method: ").append(logInfo.getClassName()).append(".").append(logInfo.getMethodName()).append("\n");
sb.append("URL: ").append(logInfo.getRequestUrl()).append("\n");
sb.append("HTTP Method: ").append(logInfo.getRequestMethod()).append("\n");
sb.append("Client IP: ").append(logInfo.getClientIp()).append("\n");
sb.append("Execution Time: ").append(logInfo.getExecutionTime()).append("ms\n");
sb.append("Start Time: ").append(new Date(logInfo.getStartTime())).append("\n");
sb.append("End Time: ").append(new Date(logInfo.getEndTime())).append("\n");
sb.append("Thread: ").append(logInfo.getThreadName()).append("\n");
sb.append("==================");
return sb.toString();
}

/**
* 格式化异常日志为文本
*/
private String formatExceptionLogAsText(ExceptionLogInfo logInfo) {
StringBuilder sb = new StringBuilder();
sb.append("=== 请求异常 ===\n");
sb.append("TraceId: ").append(logInfo.getTraceId()).append("\n");
sb.append("SpanId: ").append(logInfo.getSpanId()).append("\n");
sb.append("Layer: ").append(logInfo.getLayer()).append("\n");
sb.append("Method: ").append(logInfo.getClassName()).append(".").append(logInfo.getMethodName()).append("\n");
sb.append("URL: ").append(logInfo.getRequestUrl()).append("\n");
sb.append("HTTP Method: ").append(logInfo.getRequestMethod()).append("\n");
sb.append("Client IP: ").append(logInfo.getClientIp()).append("\n");
sb.append("Exception: ").append(logInfo.getException().getClass().getSimpleName()).append("\n");
sb.append("Message: ").append(logInfo.getException().getMessage()).append("\n");
sb.append("Execution Time: ").append(logInfo.getExecutionTime()).append("ms\n");
sb.append("Start Time: ").append(new Date(logInfo.getStartTime())).append("\n");
sb.append("End Time: ").append(new Date(logInfo.getEndTime())).append("\n");
sb.append("Thread: ").append(logInfo.getThreadName()).append("\n");
sb.append("==================");
return sb.toString();
}

/**
* 格式化业务日志为文本
*/
private String formatBusinessLogAsText(BusinessLogInfo logInfo) {
StringBuilder sb = new StringBuilder();
sb.append("=== 业务日志 ===\n");
sb.append("TraceId: ").append(logInfo.getTraceId()).append("\n");
sb.append("SpanId: ").append(logInfo.getSpanId()).append("\n");
sb.append("Business Type: ").append(logInfo.getBusinessType()).append("\n");
sb.append("Business Data: ").append(logInfo.getBusinessData()).append("\n");
sb.append("Timestamp: ").append(new Date(logInfo.getTimestamp())).append("\n");
sb.append("Thread: ").append(logInfo.getThreadName()).append("\n");
sb.append("==================");
return sb.toString();
}

/**
* 格式化性能日志为文本
*/
private String formatPerformanceLogAsText(PerformanceLogInfo logInfo) {
StringBuilder sb = new StringBuilder();
sb.append("=== 性能日志 ===\n");
sb.append("TraceId: ").append(logInfo.getTraceId()).append("\n");
sb.append("SpanId: ").append(logInfo.getSpanId()).append("\n");
sb.append("Metrics: ").append(logInfo.getMetrics()).append("\n");
sb.append("Timestamp: ").append(new Date(logInfo.getTimestamp())).append("\n");
sb.append("Thread: ").append(logInfo.getThreadName()).append("\n");
sb.append("==================");
return sb.toString();
}
}

4.2 日志输出器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
* 日志输出器
* 负责输出各种类型的日志
*/
@Component
@Slf4j
public class LogOutputter {

private final LogOutputConfig outputConfig;
private final Map<LogLevel, Logger> loggerMap = new HashMap<>();

/**
* 输出日志
*/
public void output(String logContent, LogLevel level) {
try {
switch (outputConfig.getOutputType()) {
case CONSOLE:
outputToConsole(logContent, level);
break;
case FILE:
outputToFile(logContent, level);
break;
case DATABASE:
outputToDatabase(logContent, level);
break;
case MQ:
outputToMQ(logContent, level);
break;
case MULTIPLE:
outputToMultiple(logContent, level);
break;
default:
outputToConsole(logContent, level);
}

} catch (Exception e) {
log.error("输出日志失败", e);
}
}

/**
* 输出到控制台
*/
private void outputToConsole(String logContent, LogLevel level) {
try {
Logger logger = getLogger(level);

switch (level) {
case DEBUG:
logger.debug(logContent);
break;
case INFO:
logger.info(logContent);
break;
case WARN:
logger.warn(logContent);
break;
case ERROR:
logger.error(logContent);
break;
default:
logger.info(logContent);
}

} catch (Exception e) {
log.error("输出到控制台失败", e);
}
}

/**
* 输出到文件
*/
private void outputToFile(String logContent, LogLevel level) {
try {
// 这里可以实现文件输出逻辑
// 简化实现,记录到日志
log.info("文件输出: {} - {}", level, logContent);

} catch (Exception e) {
log.error("输出到文件失败", e);
}
}

/**
* 输出到数据库
*/
private void outputToDatabase(String logContent, LogLevel level) {
try {
// 这里可以实现数据库输出逻辑
// 简化实现,记录到日志
log.info("数据库输出: {} - {}", level, logContent);

} catch (Exception e) {
log.error("输出到数据库失败", e);
}
}

/**
* 输出到消息队列
*/
private void outputToMQ(String logContent, LogLevel level) {
try {
// 这里可以实现消息队列输出逻辑
// 简化实现,记录到日志
log.info("消息队列输出: {} - {}", level, logContent);

} catch (Exception e) {
log.error("输出到消息队列失败", e);
}
}

/**
* 输出到多个目标
*/
private void outputToMultiple(String logContent, LogLevel level) {
try {
// 输出到控制台
outputToConsole(logContent, level);

// 输出到文件
outputToFile(logContent, level);

// 输出到数据库
outputToDatabase(logContent, level);

} catch (Exception e) {
log.error("输出到多个目标失败", e);
}
}

/**
* 获取日志记录器
*/
private Logger getLogger(LogLevel level) {
return loggerMap.computeIfAbsent(level, k -> {
switch (k) {
case DEBUG:
return LoggerFactory.getLogger("DEBUG");
case INFO:
return LoggerFactory.getLogger("INFO");
case WARN:
return LoggerFactory.getLogger("WARN");
case ERROR:
return LoggerFactory.getLogger("ERROR");
default:
return LoggerFactory.getLogger("DEFAULT");
}
});
}
}

五、实战应用与最佳实践

5.1 请求链路日志实战示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
* 请求链路日志实战示例
*/
@RestController
@RequestMapping("/api/request-log")
@Slf4j
public class RequestLogExample {

private final LogManager logManager;
private final TraceManager traceManager;

/**
* 演示请求链路日志
*/
@PostMapping("/demonstrate")
public ResponseEntity<RequestLogDemoResult> demonstrateRequestLog(@RequestBody RequestLogDemoRequest request) {
try {
// 1. 获取当前链路信息
String traceId = traceManager.getCurrentTraceId();
String spanId = traceManager.getCurrentSpanId();

// 2. 记录业务日志
logManager.logBusiness(traceId, spanId, "REQUEST_DEMO", request);

// 3. 执行业务逻辑
String result = processRequest(request);

// 4. 记录业务日志
logManager.logBusiness(traceId, spanId, "RESPONSE_DEMO", result);

RequestLogDemoResult demoResult = RequestLogDemoResult.builder()
.traceId(traceId)
.spanId(spanId)
.result(result)
.success(true)
.build();

return ResponseEntity.ok(demoResult);

} catch (Exception e) {
log.error("请求链路日志演示失败", e);
return ResponseEntity.badRequest().build();
}
}

/**
* 演示链路追踪
*/
@GetMapping("/demonstrate-trace")
public ResponseEntity<TraceDemoResult> demonstrateTrace() {
try {
// 1. 获取当前链路信息
String traceId = traceManager.getCurrentTraceId();
String spanId = traceManager.getCurrentSpanId();

// 2. 创建子Span
String childSpanId = traceManager.createChildSpan("CHILD_OPERATION");

// 3. 执行业务逻辑
String result = processChildOperation();

// 4. 完成子Span
traceManager.finishSpan();

TraceDemoResult demoResult = TraceDemoResult.builder()
.traceId(traceId)
.spanId(spanId)
.childSpanId(childSpanId)
.result(result)
.success(true)
.build();

return ResponseEntity.ok(demoResult);

} catch (Exception e) {
log.error("链路追踪演示失败", e);
return ResponseEntity.badRequest().build();
}
}

/**
* 演示性能监控
*/
@GetMapping("/demonstrate-performance")
public ResponseEntity<PerformanceDemoResult> demonstratePerformance() {
try {
// 1. 获取当前链路信息
String traceId = traceManager.getCurrentTraceId();
String spanId = traceManager.getCurrentSpanId();

// 2. 模拟耗时操作
long startTime = System.currentTimeMillis();
Thread.sleep(1000); // 模拟1秒的耗时操作
long endTime = System.currentTimeMillis();

// 3. 记录性能日志
PerformanceMetrics metrics = PerformanceMetrics.builder()
.key("DEMO_OPERATION")
.className("RequestLogExample")
.methodName("demonstratePerformance")
.layer("CONTROLLER")
.requestCount(1)
.totalExecutionTime(endTime - startTime)
.averageExecutionTime(endTime - startTime)
.maxExecutionTime(endTime - startTime)
.minExecutionTime(endTime - startTime)
.successCount(1)
.errorCount(0)
.lastExecutionTime(startTime)
.build();

logManager.logPerformance(traceId, spanId, metrics);

PerformanceDemoResult demoResult = PerformanceDemoResult.builder()
.traceId(traceId)
.spanId(spanId)
.executionTime(endTime - startTime)
.success(true)
.build();

return ResponseEntity.ok(demoResult);

} catch (Exception e) {
log.error("性能监控演示失败", e);
return ResponseEntity.badRequest().build();
}
}

/**
* 处理请求
*/
private String processRequest(RequestLogDemoRequest request) {
try {
// 模拟业务处理
Thread.sleep(100);
return "处理结果: " + request.getData();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("处理请求失败", e);
}
}

/**
* 处理子操作
*/
private String processChildOperation() {
try {
// 模拟子操作
Thread.sleep(200);
return "子操作结果";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("处理子操作失败", e);
}
}
}

5.2 AOP请求链路日志最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/**
* AOP请求链路日志最佳实践
*/
@Component
@Slf4j
public class RequestLogBestPractices {

private final LogManager logManager;
private final TraceManager traceManager;
private final PerformanceMonitor performanceMonitor;
private final ExceptionAnalyzer exceptionAnalyzer;

/**
* AOP请求链路日志最佳实践指南
*/
public void demonstrateBestPractices() {
log.info("=== AOP请求链路日志最佳实践指南 ===");

// 1. 正确使用AOP切面
demonstrateAOPUsage();

// 2. 链路追踪最佳实践
demonstrateTraceBestPractices();

// 3. 性能监控最佳实践
demonstratePerformanceBestPractices();

// 4. 异常处理最佳实践
demonstrateExceptionBestPractices();

// 5. 日志输出最佳实践
demonstrateLogOutputBestPractices();
}

/**
* 正确使用AOP切面
*/
private void demonstrateAOPUsage() {
log.info("--- 正确使用AOP切面 ---");

try {
// 1. 使用@RequestLog注解
@RequestLog("DEMO_OPERATION")
public String demoOperation() {
// 业务逻辑
return "操作结果";
}

// 2. 使用@Around注解
@Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object aroundRequestMapping(ProceedingJoinPoint joinPoint) throws Throwable {
// 处理请求
return joinPoint.proceed();
}

// 3. 使用@Before和@After注解
@Before("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void beforeRequestMapping(JoinPoint joinPoint) {
// 请求前处理
}

@After("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void afterRequestMapping(JoinPoint joinPoint) {
// 请求后处理
}

log.info("AOP切面使用示例完成");

} catch (Exception e) {
log.error("AOP切面使用示例失败", e);
}
}

/**
* 链路追踪最佳实践
*/
private void demonstrateTraceBestPractices() {
log.info("--- 链路追踪最佳实践 ---");

try {
// 1. 生成TraceId
String traceId = traceManager.generateTraceId();
log.info("生成TraceId: {}", traceId);

// 2. 生成SpanId
String spanId = traceManager.generateSpanId();
log.info("生成SpanId: {}", spanId);

// 3. 设置链路上下文
RequestLogContext context = RequestLogContext.builder()
.layer("DEMO")
.className("RequestLogBestPractices")
.methodName("demonstrateTraceBestPractices")
.startTime(System.currentTimeMillis())
.build();

traceManager.setTraceContext(traceId, spanId, context);

// 4. 创建子Span
String childSpanId = traceManager.createChildSpan("CHILD_OPERATION");
log.info("创建子Span: {}", childSpanId);

// 5. 完成Span
traceManager.finishSpan();

// 6. 清理链路上下文
traceManager.clearTraceContext();

log.info("链路追踪最佳实践示例完成");

} catch (Exception e) {
log.error("链路追踪最佳实践示例失败", e);
}
}

/**
* 性能监控最佳实践
*/
private void demonstratePerformanceBestPractices() {
log.info("--- 性能监控最佳实践 ---");

try {
// 1. 开始性能监控
RequestLogContext context = RequestLogContext.builder()
.layer("DEMO")
.className("RequestLogBestPractices")
.methodName("demonstratePerformanceBestPractices")
.startTime(System.currentTimeMillis())
.build();

performanceMonitor.startMonitoring(context);

// 2. 模拟业务操作
Thread.sleep(100);

// 3. 更新上下文
context.setExecutionTime(100);
context.setSuccess(true);

// 4. 结束性能监控
performanceMonitor.endMonitoring(context, true);

// 5. 获取性能指标
Map<String, PerformanceMetrics> metrics = performanceMonitor.getMetrics();
log.info("性能指标: {}", metrics);

log.info("性能监控最佳实践示例完成");

} catch (Exception e) {
log.error("性能监控最佳实践示例失败", e);
}
}

/**
* 异常处理最佳实践
*/
private void demonstrateExceptionBestPractices() {
log.info("--- 异常处理最佳实践 ---");

try {
// 1. 模拟异常
RequestLogContext context = RequestLogContext.builder()
.layer("DEMO")
.className("RequestLogBestPractices")
.methodName("demonstrateExceptionBestPractices")
.startTime(System.currentTimeMillis())
.build();

try {
// 模拟业务异常
throw new RuntimeException("模拟业务异常");
} catch (Exception e) {
// 2. 分析异常
exceptionAnalyzer.analyzeException(context, e);

// 3. 获取异常统计
ExceptionStatistics statistics = exceptionAnalyzer.getExceptionStatistics();
log.info("异常统计: {}", statistics);
}

log.info("异常处理最佳实践示例完成");

} catch (Exception e) {
log.error("异常处理最佳实践示例失败", e);
}
}

/**
* 日志输出最佳实践
*/
private void demonstrateLogOutputBestPractices() {
log.info("--- 日志输出最佳实践 ---");

try {
// 1. 记录请求日志
String traceId = traceManager.getCurrentTraceId();
String spanId = traceManager.getCurrentSpanId();

logManager.logBusiness(traceId, spanId, "DEMO_OPERATION", "演示数据");

// 2. 记录性能日志
PerformanceMetrics metrics = PerformanceMetrics.builder()
.key("DEMO_OPERATION")
.className("RequestLogBestPractices")
.methodName("demonstrateLogOutputBestPractices")
.layer("DEMO")
.requestCount(1)
.totalExecutionTime(100)
.averageExecutionTime(100)
.maxExecutionTime(100)
.minExecutionTime(100)
.successCount(1)
.errorCount(0)
.lastExecutionTime(System.currentTimeMillis())
.build();

logManager.logPerformance(traceId, spanId, metrics);

log.info("日志输出最佳实践示例完成");

} catch (Exception e) {
log.error("日志输出最佳实践示例失败", e);
}
}
}

六、总结

本文深入探讨了SpringBoot中AOP请求链路日志的架构设计与实战应用。通过构建企业级的AOP请求链路日志框架,我们实现了:

  1. 统一日志打印:通过AOP切面实现统一的请求日志打印,支持Controller、Service、Repository等各层
  2. 链路追踪:提供完整的TraceId和SpanId生成和管理,支持父子Span关系
  3. 性能监控:实时监控请求执行时间、成功率等性能指标
  4. 异常分析:自动分析和统计异常信息,提供异常告警能力
  5. 灵活输出:支持多种日志格式和输出方式,满足不同场景需求

通过这套企业级的AOP请求链路日志架构,我们能够全面监控和追踪请求链路,提供完整的系统可观测性。随着微服务架构和分布式系统的不断发展,构建可观测、可追踪的日志体系将成为企业级架构师必须掌握的核心技能。

在实际应用中,建议遵循AOP请求链路日志的最佳实践,合理配置日志级别和输出方式,及时分析性能指标和异常信息,并通过监控和告警工具确保系统的稳定运行。只有这样,才能真正发挥AOP请求链路日志的价值,构建高质量的企业级应用系统。