From 4af3f3d161dbe79b439a9aa7e9dfdbdc84a76ca9 Mon Sep 17 00:00:00 2001 From: irving Date: Mon, 27 Oct 2025 22:23:29 -0400 Subject: [PATCH] improve logging, now correctly logs the status in result --- .../advice/BusinessResultCaptureAdvice.java | 68 +++++++++++++++++++ .../RequestLoggingInterceptor.java | 60 ++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 play-common/src/main/java/com/starry/common/advice/BusinessResultCaptureAdvice.java diff --git a/play-common/src/main/java/com/starry/common/advice/BusinessResultCaptureAdvice.java b/play-common/src/main/java/com/starry/common/advice/BusinessResultCaptureAdvice.java new file mode 100644 index 0000000..d98d46a --- /dev/null +++ b/play-common/src/main/java/com/starry/common/advice/BusinessResultCaptureAdvice.java @@ -0,0 +1,68 @@ +package com.starry.common.advice; + +import com.starry.common.interceptor.RequestLoggingInterceptor; +import com.starry.common.result.R; +import com.starry.common.result.TypedR; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.lang.Nullable; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +import javax.servlet.http.HttpServletRequest; + +/** + * Captures business result metadata from standard API wrappers so the + * request logging interceptor can log based on business outcome rather than + * just the HTTP status code. + */ +@ControllerAdvice +public class BusinessResultCaptureAdvice implements ResponseBodyAdvice { + + @Override + public boolean supports(@Nullable MethodParameter returnType, + @Nullable Class> converterType) { + // Inspect every response; we'll short-circuit in beforeBodyWrite if the body isn't one we care about. + return true; + } + + @Override + public Object beforeBodyWrite(@Nullable Object body, + @Nullable MethodParameter returnType, + @Nullable MediaType selectedContentType, + @Nullable Class> selectedConverterType, + @Nullable ServerHttpRequest request, + @Nullable ServerHttpResponse response) { + + Object candidate = extractBody(body); + + RequestLoggingInterceptor.BusinessResult businessResult = null; + if (candidate instanceof R) { + R r = (R) candidate; + businessResult = new RequestLoggingInterceptor.BusinessResult(r.isSuccess(), r.getCode(), r.getMessage()); + } else if (candidate instanceof TypedR) { + TypedR typedR = (TypedR) candidate; + businessResult = new RequestLoggingInterceptor.BusinessResult(typedR.isSuccess(), typedR.getCode(), typedR.getMessage()); + } + + if (businessResult != null && request instanceof ServletServerHttpRequest) { + HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest(); + servletRequest.setAttribute(RequestLoggingInterceptor.BUSINESS_RESULT_ATTRIBUTE, businessResult); + } + + return body; + } + + @Nullable + private Object extractBody(@Nullable Object body) { + if (body instanceof ResponseEntity) { + return ((ResponseEntity) body).getBody(); + } + return body; + } +} diff --git a/play-common/src/main/java/com/starry/common/interceptor/RequestLoggingInterceptor.java b/play-common/src/main/java/com/starry/common/interceptor/RequestLoggingInterceptor.java index 28fe9b9..b88ae78 100644 --- a/play-common/src/main/java/com/starry/common/interceptor/RequestLoggingInterceptor.java +++ b/play-common/src/main/java/com/starry/common/interceptor/RequestLoggingInterceptor.java @@ -23,6 +23,7 @@ public class RequestLoggingInterceptor implements HandlerInterceptor { private static final Logger log = LoggerFactory.getLogger(RequestLoggingInterceptor.class); private static final String START_TIME_ATTRIBUTE = "startTime"; + public static final String BUSINESS_RESULT_ATTRIBUTE = "requestLoggingBusinessResult"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) @@ -97,9 +98,16 @@ public class RequestLoggingInterceptor implements HandlerInterceptor { int status = response.getStatus(); String statusText = getStatusText(status); + BusinessResult businessResult = (BusinessResult) request.getAttribute(BUSINESS_RESULT_ATTRIBUTE); + if (businessResult != null) { + request.removeAttribute(BUSINESS_RESULT_ATTRIBUTE); + } + if (ex != null) { log.error("Request completed with error: {} {} - {} {} ({}ms) - Exception: {}", method, uri, status, statusText, duration, ex.getMessage()); + } else if (businessResult != null) { + logWithBusinessResult(method, uri, status, statusText, duration, businessResult); } else if (status >= 400) { log.warn("Request completed with error: {} {} - {} {} ({}ms)", method, uri, status, statusText, duration); @@ -196,6 +204,58 @@ public class RequestLoggingInterceptor implements HandlerInterceptor { } } + private void logWithBusinessResult(String method, String uri, int status, String statusText, + long duration, BusinessResult businessResult) { + String template = "Request completed: {} {} - {} {} ({}ms) businessCode={} success={} message={}"; + if (isBusinessError(businessResult)) { + log.error(template, method, uri, status, statusText, duration, + businessResult.getCode(), businessResult.isSuccess(), businessResult.getMessage()); + } else if (isBusinessWarn(businessResult)) { + log.warn(template, method, uri, status, statusText, duration, + businessResult.getCode(), businessResult.isSuccess(), businessResult.getMessage()); + } else { + log.info(template, method, uri, status, statusText, duration, + businessResult.getCode(), businessResult.isSuccess(), businessResult.getMessage()); + } + } + + private boolean isBusinessError(BusinessResult businessResult) { + Integer code = businessResult.getCode(); + return code != null && code >= 500; + } + + private boolean isBusinessWarn(BusinessResult businessResult) { + Integer code = businessResult.getCode(); + if (code != null) { + return code >= 400; + } + return !businessResult.isSuccess(); + } + + public static final class BusinessResult { + private final boolean success; + private final Integer code; + private final String message; + + public BusinessResult(boolean success, Integer code, String message) { + this.success = success; + this.code = code; + this.message = message; + } + + public boolean isSuccess() { + return success; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } + } + /** * 判断是否为安全的请求头(不包含敏感信息) */