Spring Boot Prometheus Converter 406 Not Acceptable

2019. 4. 6. 11:09·Development/Spring
반응형

개요

Spring Boot Project에 actuator를 적용한 뒤, prometheus micrometer를 적용했을 때 WebMvcConfigurationSupport 를 customizing 하게 되면 발생하는 문제에 대한 해결책이다.

해당 문제를 보려면 일단 Spring Boot Project를 생성하자. (Spring boot Initializer를 사용하면 편리하다)

그 뒤, 아래의 dependency를 추가한다.

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- Micrometer Prometheus registry  -->
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>

application.properties에 아래 내용을 추가한다(추가하지 않으면 /actuator/prometheus가 exposure되지 않아서 접근할 수 없다)

management.endpoints.web.exposure.include=*

그렇게 되면 아래의 path로 prometheus exporter 를 접근할 수 있게 된다(기본 8080 포트 사용 시)

localhost:8080/actuator/prometheus

문제

자, 이 상태로 무언가 WebMvcConfigurationSupport 의 ObjectMapper를 수정하고 싶을 때(default serialize, deserialize 등의 행동을 바꾸고자 할 때 간혹 사용된다) 아래와 같은 method를 override를 하게 된다.

@Configuration
public class WebConfig extends WebMvcConfigurationSupport {

    @Override
    public void configureMessageConverters(List converters) {

        final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        final ObjectMapper objectMapper = new ObjectMapper();

        // ObjectMapper Settings(JODA)
        objectMapper.registerModule(new JodaModule());
        objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.
                WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
        converter.setObjectMapper(objectMapper);

        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.serializationInclusion(JsonInclude.Include.NON_EMPTY);

        // Add settings to converter, builder
        converters.add(converter);
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }

}

위와 같은 override를 해서 Spring 내부의 MessageConverter 를 수정했을 경우 API 등은 잘 동작할 수 있다.

하지만, prometheus exporter에서 사용하는 Content Type은 text/plain 을 사용하게 된다.

백문이 불여일견, 위 Config class와 함께 prometheus exporter 페이지를 접근해보자(localhost:8080/actuator/prometheus)

image-20190323145710182

위와 같이 Http 406 Not Acceptable 과 함께 나오지 않는다.

해결방법

  1. MappingJackson2HttpMessageConverter 에 Content Type을 지정한다

JSON은 정상적으로 나오니, Content Type에 TEXT/PLIAN 을 추가하면 되지 않을까?

converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN));

 

엇 무언가 나온다. 근데 포맷팅이 이상하다

TEXT/HTML의 내용을 JSON형식으로 마셜링을 해버린것이다..;

이렇게 된 경우, prometheus server에서 이를 수집할 수가 없다.(formatting이 맞지 않기 때문)

사용하지 않도록 하자 ..

  1. StringHttpMessageConverter 를 converter에 추가한다
converters.add(new StringHttpMessageConverter());

를 아까 생성한 Config 클래스에 추가를 해주자.

 

추가가 잘 되면 드디어! 정상적인 format으로 나오게 된다.

그럼 StringHttpMessageConverter 는 뭘하는놈일까

내부를 열어보면

    public StringHttpMessageConverter(Charset defaultCharset) {
        super(defaultCharset, new MediaType[]{MediaType.TEXT_PLAIN, MediaType.ALL});
        this.writeAcceptCharset = true;
    }

기본적으로 TEXT_PLAIN 과 모든 MediaType을 가지고 생성이 된다.

    protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
        if (this.writeAcceptCharset) {
            outputMessage.getHeaders().setAcceptCharset(this.getAcceptedCharsets());
        }

        Charset charset = this.getContentTypeCharset(outputMessage.getHeaders().getContentType());
        StreamUtils.copy(str, charset, outputMessage.getBody());
    }

그리고 해당 함수에서 Response로 값을 write 하는 부분을 찾아보게 되면 위와 같이 String으로 convert를 해서 내보내는 것을 알 수 있다.

    protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
        Charset charset = this.getContentTypeCharset(inputMessage.getHeaders().getContentType());
        return StreamUtils.copyToString(inputMessage.getBody(), charset);
    }

읽을땐 역시 반대로 String으로 convert를 한 뒤 String으로 전달을 해준다.

반응형
저작자표시 동일조건 (새창열림)

'Development > Spring' 카테고리의 다른 글

Spring Redis Template Transaction  (2) 2021.09.09
Spring RequestContextHolder  (9) 2020.07.05
Spring Password Encoder  (4) 2019.04.06
Dispatcher Servlet  (0) 2019.04.06
[JAVA/Spring] BeanUtils 관련  (2) 2018.07.20
'Development/Spring' 카테고리의 다른 글
  • Spring RequestContextHolder
  • Spring Password Encoder
  • Dispatcher Servlet
  • [JAVA/Spring] BeanUtils 관련
@곰팡
@곰팡
Java Backend Developer
  • @곰팡
    곰팡이 먼지연구소
    @곰팡
  • 전체
    오늘
    어제
    • 분류 전체보기 (55)
      • Daily Life (1)
        • 잡담 (1)
      • IT기업 입사 (0)
      • Development (52)
        • Java (24)
        • Spring (6)
        • Web (3)
        • OS (6)
        • Algorithm (4)
        • 이것저것 끄적끄적 (3)
        • Netty & FlatBuffers (3)
        • Database (2)
        • Dev-ops, Monitoring (1)
      • Labatory (0)
        • Test Bed 1 (0)
  • 블로그 메뉴

    • 메인
    • 카테고리
    • 태그
    • 방명록
    • 글 작성
    • 관리자
  • 링크

    • linkedIn
    • github
  • 공지사항

  • 인기 글

  • 태그

    타코야끼
    Spring
    flatbuffer
    일본
    일본여행
    springboot
    北九州
    해외여행
    kitakyusu
    linux
    HashMap
    java
    자바
    고쿠라역
    북큐슈
    고쿠라
    Spring Boot
    prometheus
    기타큐슈
    皿倉山
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
@곰팡
Spring Boot Prometheus Converter 406 Not Acceptable
상단으로

티스토리툴바