Contents
Intro
Once I had a task to enable Apache Camel metrics. Those metrics was purposed to count number of rejected and passed request through routes.
Input:
Spring Boot (2.5.6) for dependency injection on a service, security, providing REST API for settings.
Apache Camel (3.13.0) for routing, throttling and passing metrics about each route to /actuator/prometheus (in our case).
Micrometer (1.18.0) for collecting metrics and providing them for gathering through /actuator/prometheus.\
Popular approach
Most common approach, which I have met over the internet (at least in articles since 2016 and in a lots of videos) is next:
Adding next dependency:
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-micrometer-starter</artifactId>
</dependency>
Adding next propery into application.properties file:
camel.component.metrics.metric-registry=prometheusMeterRegistry
Adding next code into @Configuration class:
@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) {
}
};
}
By messages and results on the videos I have seen that this approach should lead to adding default metrics of Apache Camel on the page /actuator/prometheus such as CamelMessageHistory_seconds_count. Also it should enable the ability to add custom metrics though something like that micrometer:counter:simple.counter
Problem
In my case I had a problem with this approach. It just doesn't work on my project.
Path to find the solution
Made an assumption that approach stated earlier was written some time ago and combined different versions of dependencies (at that time I had some flexibility in making those decisions):
Spring Boot 2.4.2 - 2.5.6
Apache Camel 3.8.0 - 3.13.0
io.micrometer 1.7.2 - 1.8.0
Checked my code for typos. During that process found several typos in different related placed over the internet including Apache Camel documentation (for example it was about similarity of syntax metrics: and micrometer)
Lots of debugging of different places of my service and Apache Camel, Spring Boot, Micrometer.
During the debugging I have figured out that micrometer: bean "doesn't see" prometheusMeterRegistry.
Tried to add PrometheusMeterRegistry by myself:
@Bean(name = { MicrometerConstants.METRICS_REGISTRY_NAME })
public PrometheusMeterRegistry prometheusMeterRegistry() {
return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
}
Previous step didn't solve the problem completely. I have received metrics through /actuator/metrics (both default Apache Camel metrics and added with java code). But I have no Apache Camel metrics pulled from /actuator/prometheus. And there is no metrics ("simple.counter") added with micrometer:counter:simple.counter.
Metrics definitions can be added with next code:
@Bean
public void initCounter(MeterRegistry meterRegistry) {
Counter.builder("simple.counter")
.register(meterRegistry);
}
After previos step there no those metrics at /actuator/prometheus they have only constant value - 0 at /actuator/metrics.
After some more debugging I have found out that there is 3 MeterRegistry objects in CamelContext (one JmxMeterRegistry and two PrometheusMeterRegistry). This is an indicator that there is an extra PrometheusMeterRegistry added during app initialization.
Yep, there is spring-boot-actuator-autoconfigure which has code with initialization of it's own PrometheusMeterRegistry.
Final (my) solution
Final solution looks something like this:
Add dependency
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-micrometer-starter</artifactId>
</dependency>
Add this @Bean definition:
@Bean(name = { MicrometerConstants.METRICS_REGISTRY_NAME, "prometheusMeterRegistry" })
public PrometheusMeterRegistry prometheusMeterRegistry(
PrometheusConfig prometheusConfig, CollectorRegistry collectorRegistry, Clock clock) {
return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock);
}
With this approach we're having only two MeterRegistry objects into the context - one JmxMeterRegistry and one PrometheusMeterRegistry. And this PrometheusMeterRegistry is visible and accessible for both Apache Camel and Spring Boot Actuator.
And we finally able to see the results of this solution - at /actuator/prometheus there is accessible Apache Camel default metrics. Also custom metrics can be added and updated with common Apache Camel's syntax:
Conclusion
During this article I've shown my way and working solution to integrate Apache Camel and Spring Boot Actuator metrics with passing those metrics to Prometheus.