fastjson序列化导致prometheus返回监控数据格式错乱

在springboot 中集成prometheus的监控时遇见问题。
因为项目里在StaticResourceConfig配置了fastjson 序列化,导致prometheus接口返回数据被转化为json格式,无法正常展示
正常情况格式应为这种

实际返回了这种

StaticResourceConfig 配置如下:

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                converters.remove(converter);
            }
        }
        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(getFastJsonConverter());
    }

    private FastJsonHttpMessageConverter getFastJsonConverter() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        List<MediaType> supportedMediaTypes = new ArrayList<>();
        //提供对admin的类型支持mediaType
        MediaType mediaType = MediaType.valueOf("application/vnd.spring-boot.actuator.v2+json");
        supportedMediaTypes.add(mediaType);
        supportedMediaTypes.add(MediaType.ALL);
        converter.setSupportedMediaTypes(supportedMediaTypes);
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.DisableCircularReferenceDetect);
        //日期格式化
        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        ParserConfig parserConfig = ParserConfig.getGlobalInstance();
        parserConfig.setSafeMode(true);
        fastJsonConfig.setParserConfig(parserConfig);
        converter.setFastJsonConfig(fastJsonConfig);

        return converter;
    }

解决办法

通过增加一层转发,调用监控接口获取到数据,然后反序列化为原来的格式,然后通过response.write方式返回监控结果。
因为采用response.write的方式,不会被spring mvc的HttpMessageConverter所拦截,所以可以直接返回plain/text格式的数据

package com.yuanian.monitor;

import com.alibaba.fastjson.JSON;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;

/**
 * @author liujy
 * @since Wed Feb 24 17:55:16 CST 2021
 */
@RestController
@RequestMapping("prometheus")
public class PrometheusController {
    @Value("${server.servlet.context-path}")
    private String contextPath;
    @Value("${server.port}")
    private Integer port;

    @GetMapping(path = "/metrics", produces = MediaType.TEXT_PLAIN_VALUE)
    public void healthz(HttpServletResponse response) throws URISyntaxException {
        RestTemplate restTemplate = new RestTemplate();
        StringBuilder prometheusUrl = new StringBuilder("http://127.0.0.1:");
        prometheusUrl.append(port);
        prometheusUrl.append(contextPath);
        prometheusUrl.append("/actuator/prometheus");

        ResponseEntity<String> responseEntity = restTemplate.getForEntity(prometheusUrl.toString(), String.class);
        String body = responseEntity.getBody();
        String s = JSON.parseObject(body, String.class);

        try (BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
            bos.write(s.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

posted @ 2021-03-09 13:36  夜洛IT后端技术分享  阅读(1632)  评论(1编辑  收藏  举报