feat(selfop): expose opt-in test query timing headers

This commit is contained in:
2026-10-13 10:42:19 +08:00
parent 4c9878c338
commit c13bf96cb9
3 changed files with 75 additions and 4 deletions
@@ -39,12 +39,16 @@ final class QueryDiagnostics {
int statementDepth;
MethodTiming timing(String method) { return methods.computeIfAbsent(method, MethodTiming::new); }
String json(String endpoint, String requestId, int status, boolean failed) {
return json(endpoint, requestId, status, failed, "REQUEST_COMPLETE");
}
String json(String endpoint, String requestId, int status, boolean failed, String capturePoint) {
long total = System.nanoTime() - started;
long executor = methods.values().stream().mapToLong(t -> t.executor.nanos).sum();
Map<String,Object> report = new LinkedHashMap<>();
report.put("event", "SELFOP_QUERY_DIAGNOSTICS"); report.put("endpoint", endpoint);
report.put("requestId", requestId != null && requestId.matches("[A-Za-z0-9._:-]{1,128}") ? requestId : null);
report.put("httpStatus", status); report.put("escapedException", failed);
report.put("capturePoint", capturePoint);
report.put("requestNanos", total); report.put("unattributedNanos", Math.max(0, total-executor));
report.put("timingMeaning", "CLIENT_EXECUTOR_AND_STATEMENT_INCLUDING_MAPPING_NOT_SERVER_DB_TIME");
report.put("poolWaitAttribution", "NOT_MEASURED_PER_REQUEST"); report.put("methods", methods);
@@ -0,0 +1,35 @@
package com.baiyue.lastleg.selfoperated.analytics.query.diagnostics;
import com.baiyue.common.web.CorrelationContext;
import org.slf4j.MDC;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.*;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.util.Map;
/** Opt-in diagnostic snapshot before serialization; never changes the response body. */
@RestControllerAdvice
@ConditionalOnExpression("'${DEPLOY_ENV:}' == 'test' && ${baiyue.self-operated-analytics.query-diagnostics.enabled:false}")
public final class QueryDiagnosticsResponseAdvice implements ResponseBodyAdvice<Object> {
public static final String HEADER = "X-Selfop-Query-Diagnostics";
private static final String BASE = "/api/platform/v1/last-leg/self-operated-analytics/";
private static final Map<String,String> ENDPOINTS = Map.of(BASE+"dashboard", "DASHBOARD",
BASE+"sku-sales-summary", "SUMMARY", BASE+"inventory-coverage", "INVENTORY");
@Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return QueryDiagnostics.CURRENT.get() != null;
}
@Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType contentType,
Class<? extends HttpMessageConverter<?>> converterType, ServerHttpRequest request, ServerHttpResponse response) {
var state = QueryDiagnostics.CURRENT.get();
String endpoint = ENDPOINTS.get(request.getURI().getPath());
if (state != null && endpoint != null && request.getMethod() == org.springframework.http.HttpMethod.GET) {
int status = response instanceof ServletServerHttpResponse servlet ? servlet.getServletResponse().getStatus() : 200;
response.getHeaders().set(HEADER, state.json(endpoint, MDC.get(CorrelationContext.REQUEST_ID), status, false, "BEFORE_BODY_WRITE"));
}
return body;
}
}