受某些大厂的影响,很多开发人员只使用Http 200状态码,而在响应体的内部定义自身的响应码来表示错误信息,这样导致了现有的监控库并不能有效的监控到API的错误响应。考虑到大量API的改造工作量,所以最简单快速的方法还是改造监控的库,添加上自定义错误码的采集。
集成 Actuator
项目添加如下maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
NOTE:Actuator 1.x和2.x是不兼容的,建议使用2.x版本。
配置 Actuator Metrics
Actuator 2.x的端口默认是关闭的,需要通过配置打开,特别是生产环境更需要小心公开的API。
management:
endpoints:
web:
exposure:
include: health,info,prometheus
metrics:
tags:
application: actuator-demo #应用名称
version: 1.0.0 #应用版本
获取自定义响应码
实现ResponseBodyAdvice接口,获取自定义响应码
public class CustomizedErrorCodeControllerAdvice implements ResponseBodyAdvice<Object> {
private final Map<Class<?>, Function<Object, String>> classFunctionMap = new ConcurrentHashMap<>();
public CustomizedErrorCodeControllerAdvice(Map<Class<?>, Function<Object, String>> maps) {
classFunctionMap.putAll(maps);
}
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
// 非空判断,如果为空xxx.isAssignableFrom总是真
if (null != o && serverHttpRequest instanceof ServletServerHttpRequest) {
HttpServletRequest httpServletRequest = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest();
for (Map.Entry<Class<?>, Function<Object, String>> entry : classFunctionMap.entrySet()) {
if (entry.getKey().isAssignableFrom(o.getClass())) {
String errorCode = entry.getValue().apply(o);
httpServletRequest.setAttribute(CustomizedErrorCodeContributor.REQUEST_ATTRIBUTE, errorCode);
break;
}
}
}
return o;
}
为指标添加自定义响应码
实现WebMvcTagsContributor接口,为指标添加自定义响应码。
@Component
public class CustomizedErrorCodeContributor implements WebMvcTagsContributor {
public static final String REQUEST_ATTRIBUTE = "__actuator_demo_customized_error_code.Request.Attribute";
private static final String ERROR_CODE_TAG = "business_code";
@Override
public Iterable<Tag> getTags(HttpServletRequest request HttpServletResponse response, Object handler, Throwable exception) {
Object attr = request.getAttribute(REQUEST_ATTRIBUTE);
if (attr instanceof String) {
return Tags.of(ERROR_CODE_TAG, (String) attr);
}
return Tags.empty();
}
@Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
return Tags.empty();
}
}