Оглавление

Введение

На одном из проектов передо мной стояла задача по включению метрик-счетчиков на маршрутах при штатном прохождении и при отклонении запросов.

Дано:

  • Spring Boot (2.5.6) для инъекции зависимостей, безопасности, предоставления веб-страничек для служебных целей.

  • Apache Camel (3.13.0) для маршрутизации запросов, троттлинга, направления метрик по каждому маршруту в точку сбора (в нашем случае /actuator/prometheus).

  • Micrometer (1.18.0) для сбора метрик и выставления их по адресу /actuator/prometheus.

Популярный подход

Самый частый подход, который мне встречался в интернете (во всех статьях от 2016 года и новее, а также во многих видео) состоит в следующем:

  • Добавление следующей зависимости

<dependency>
    <groupId>org.apache.camel.springboot</groupId>
    <artifactId>camel-micrometer-starter</artifactId>
</dependency>

camel.component.metrics.metric-registry=prometheusMeterRegistry

  • Создание следующего кода в конфигурационном классе:

    @Bean
    public CamelContextConfiguration camelContextConfiguration() {

    return new CamelContextConfiguration() {
        @Override
        public void beforeApplicationStart(CamelContext camelContext) {
            camelContext.addRoutePolicyFactory(new MicrometerRoutePolicyFactory());
            camelContext.setMessageHistoryFactory(new MicrometerMessageHistoryFactory());
        }

        @Override
        public void afterApplicationStart(CamelContext camelContext) {

        }
    };
}

По сообщениям и по результатам на видео это должно приводить к появлению стандартных метрик Apache Camel на странице /actuator/prometheus, таких как CamelMessageHistory_seconds_count, и, в дальнейшем, возможности добавлять свои метрики, пользуясь синтаксисом micrometer:counter:simple.counter.

Проблема

В моём случае проблема заключается в том что у меня это не работает.

Попытки (ход) решения

  1. Попробовал учесть староватость способа приведённого выше и перебрал кучу комбинаций версий зависимостей (в данном случае у меня была некоторая гибкость):

    • Spring Boot 2.4.2 - 2.5.6

    • Apache Camel 3.8.0 - 3.13.0

    • io.micrometer 1.7.2 - 1.8.0

  2. Множество раз проверил код на опечатки. Попутно выяснил что они присутствуют во многих местах в интернете на данную тему, включая документацию Apache Camel (речь про похожесть синтаксиса метрик через metrics: и micrometer: )

  3. Много дебаггинга разных мест из моего сервиса, Apache Camel, Spring Boot, Micrometer.

  4. В процессе дебаггинга выяснилось слушатель канала micrometer: не "видит" ссылку на prometheusMeterRegistry.

  5. Попытался прописать явно добавление PrometheusMeterRegistry

@Bean(name = { MicrometerConstants.METRICS_REGISTRY_NAME })
public PrometheusMeterRegistry prometheusMeterRegistry() {
    return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
}
  1. Это не решило проблему в полной мере. По ссылке /actuator/metrics всё-таки появились искомые метрики (как дефолтные от Apache Camel, так и новые, добавленные в коде). Но на странице /actuator/prometheus метрики Apache Camel не появлялись, а также использование micrometer:counter:simple.counter не добавляет simple.counter к списку метрик.

  2. Метрики удаётся добавить в список примерно следующим способом:

@Bean
public void initCounter(MeterRegistry meterRegistry) {
    Counter.builder("simple.counter")
            .register(meterRegistry);
}
  1. Но в таком случае они не обновляются на странице /actuator/prometheus и имеют константное значение - 0.

  2. Ещё после некоторого дебага выяснилась следующая картина - в экземпляре CamelContext лежит 3 объекта MeterRegistry (один JmxMeterRegistry и два PrometheusMeterRegistry). Что говорит о том что где-то инициализируется ещё один PrometheusMeterRegistry помимо описанного выше.

  3. Так и есть, spring-boot-actuator-autoconfigure имеет свой Bean с данным типом.

Как итог - остаётся проинициализировать и для /actuator и для Apache Camel один и тот же bean.

Финальное (моё) решение

Итоговое решение выглядит так:

  • Добавить зависимость:

<dependency>
    <groupId>org.apache.camel.springboot</groupId>
    <artifactId>camel-micrometer-starter</artifactId>
    <version>${org.apache.camel.springboot.version}</version>
</dependency>
  • Объявить @Bean следующим образом

@Bean(name = { MicrometerConstants.METRICS_REGISTRY_NAME, "prometheusMeterRegistry" })
public PrometheusMeterRegistry prometheusMeterRegistry(
        PrometheusConfig prometheusConfig, CollectorRegistry collectorRegistry, Clock clock) {
    return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock);
}

В данном случае у нас среди MeterRegistry оказываются всего один JmxMeterRegistry и один PrometheusMeterRegistry который доступен и для ApacheCamel и для Spring Boot Actuator.

Также сразу заметен результат работы данного решения, а именно - по адресу /actuator/prometheus доступны как метрики Apache Camel так и кастомные:

Часть содержимого по адресу /actuator/prometheus
Часть содержимого по адресу /actuator/prometheus

Заключение

По итогу проделанной работы было найдено рабочее решение по интеграции Apache Camel метрик в Spring Boot Actuator и проброской их в Prometheus.

Спасибо за внимание.

Комментарии (3)


  1. Shmaiser
    04.12.2021 03:30
    +1

    У меня все настроено как описано в доках, ну плюс явно обновляю счетчики и таймеры в рутах когда надо:

    .to("micrometer:counter:events.counter?tags=type=my_type,my_other_tag=zzz")

    .to("micrometer:timer:events.timer?tags=type=my_type,my_other_tag=zzz")

    RoutePolicy фабрику я добавляю до старта camel context

    и плюс включить

    management.endpoint.metrics.enabled=true

    management.endpoint.prometheus.enabled=true


    1. MasteR_GeliOS Автор
      04.12.2021 11:09

      Только что попробовал сделать у себя в тестовом проекте так как вы и описали - без объявленного моим способом PrometheusMeterRegistry не срабатывает.

      Даже частичного срабатывания (когда метрики есть по адресу /actuator/metrics но не попадают или не обновляются в /actuator/prometheus) у меня не происходит.


  1. chemtech
    04.12.2021 12:57

    Спасибо за пост. Подскажите, пожалуйста, если знаете. Есть проект https://github.com/spring-petclinic/spring-petclinic-cloud

    Я пытаюсь запустить spring-petclinic-cloud в kubernetes. Получаю ошибку java.net.UnknownHostException: wavefront-proxy

    Как развернуть Spring-Petclinic-Cloud на k8s без wavefront?

    Issue есть https://github.com/spring-petclinic/spring-petclinic-cloud/issues/39