Compare commits

..

2 Commits

Author SHA1 Message Date
irving
8a9e7dc86f format
Some checks failed
Build and Push Backend / docker (push) Failing after 5s
2025-10-27 22:25:44 -04:00
irving
4af3f3d161 improve logging, now correctly logs the status in result 2025-10-27 22:23:29 -04:00
2 changed files with 127 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
package com.starry.common.advice;
import com.starry.common.interceptor.RequestLoggingInterceptor;
import com.starry.common.result.R;
import com.starry.common.result.TypedR;
import javax.servlet.http.HttpServletRequest;
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.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 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<Object> {
@Override
public boolean supports(@Nullable MethodParameter returnType,
@Nullable Class<? extends HttpMessageConverter<?>> 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<? extends HttpMessageConverter<?>> 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;
}
}

View File

@@ -23,6 +23,7 @@ public class RequestLoggingInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(RequestLoggingInterceptor.class); private static final Logger log = LoggerFactory.getLogger(RequestLoggingInterceptor.class);
private static final String START_TIME_ATTRIBUTE = "startTime"; private static final String START_TIME_ATTRIBUTE = "startTime";
public static final String BUSINESS_RESULT_ATTRIBUTE = "requestLoggingBusinessResult";
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
@@ -97,9 +98,16 @@ public class RequestLoggingInterceptor implements HandlerInterceptor {
int status = response.getStatus(); int status = response.getStatus();
String statusText = getStatusText(status); String statusText = getStatusText(status);
BusinessResult businessResult = (BusinessResult) request.getAttribute(BUSINESS_RESULT_ATTRIBUTE);
if (businessResult != null) {
request.removeAttribute(BUSINESS_RESULT_ATTRIBUTE);
}
if (ex != null) { if (ex != null) {
log.error("Request completed with error: {} {} - {} {} ({}ms) - Exception: {}", log.error("Request completed with error: {} {} - {} {} ({}ms) - Exception: {}",
method, uri, status, statusText, duration, ex.getMessage()); method, uri, status, statusText, duration, ex.getMessage());
} else if (businessResult != null) {
logWithBusinessResult(method, uri, status, statusText, duration, businessResult);
} else if (status >= 400) { } else if (status >= 400) {
log.warn("Request completed with error: {} {} - {} {} ({}ms)", log.warn("Request completed with error: {} {} - {} {} ({}ms)",
method, uri, status, statusText, duration); 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;
}
}
/** /**
* 判断是否为安全的请求头(不包含敏感信息) * 判断是否为安全的请求头(不包含敏感信息)
*/ */