Contents
- Dependencies & Auto-Configuration
- Auto-Collected Route Metrics
- Custom Counters in Routes
- Custom Timers
- Micrometer DSL in Routes
- Prometheus & Actuator Exposure
- Key Grafana Queries
- OpenTelemetry Distributed Tracing
- JMX & Camel Management
Add the following to your pom.xml (Maven) or build.gradle (Gradle). Spring Boot manages compatible versions automatically when you use the Spring Boot BOM.
<!-- camel-micrometer — auto-instruments all routes -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-micrometer-starter</artifactId>
</dependency>
<!-- Actuator + Prometheus registry -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!-- OpenTelemetry tracing -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-opentelemetry-starter</artifactId>
</dependency>
# application.yml
management:
endpoints:
web:
exposure:
include: health,prometheus,camel
metrics:
tags:
application: ${spring.application.name}
camel:
springboot:
name: order-integration-service
Once camel-micrometer-starter is on the classpath, every route is automatically instrumented. No code changes required.
| Metric | Type | Description |
| camel.exchanges.total | Counter | Total exchanges processed per route |
| camel.exchanges.succeeded.total | Counter | Successful exchanges per route |
| camel.exchanges.failed.total | Counter | Failed exchanges per route |
| camel.exchanges.inflight | Gauge | Currently in-flight exchanges |
| camel.exchange.event.notifier | Timer | Exchange processing time per route |
| camel.route.policy | Timer | Route execution time (requires RoutePolicyFactory) |
# Verify auto-collected metrics at the Prometheus endpoint
curl http://localhost:8080/actuator/prometheus | grep camel_exchanges
# camel_exchanges_total{camelContext="order-integration-service",routeId="route1",...} 42.0
# camel_exchanges_succeeded_total{...} 40.0
# camel_exchanges_failed_total{...} 2.0
The class below shows the implementation. Key points are highlighted in the inline comments.
@Component
public class OrderRoute extends RouteBuilder {
@Override
public void configure() {
from("kafka:order.created")
.routeId("order-processor")
.choice()
.when(simple("${body.totalAmount} > 1000"))
// Increment a custom counter for high-value orders
.process(exchange -> {
MeterRegistry registry = exchange.getContext()
.getRegistry().findByType(MeterRegistry.class)
.iterator().next();
Counter.builder("order.high.value")
.tag("currency", exchange.getIn().getHeader("currency", String.class))
.description("High-value orders processed")
.register(registry)
.increment();
})
.to("direct:processHighValueOrder")
.otherwise()
.to("direct:processStandardOrder");
}
}
The class below shows the implementation. Key points are highlighted in the inline comments.
@Component
public class EnrichmentRoute extends RouteBuilder {
@Autowired
private MeterRegistry meterRegistry;
@Override
public void configure() {
Timer enrichmentTimer = Timer.builder("camel.order.enrichment.duration")
.description("Time to enrich an order from external service")
.register(meterRegistry);
from("direct:enrichOrder")
.process(exchange -> {
Timer.Sample sample = Timer.start(meterRegistry);
try {
// Perform enrichment
Order enriched = enrichmentService.enrich(
exchange.getIn().getBody(Order.class));
exchange.getIn().setBody(enriched);
} finally {
sample.stop(enrichmentTimer);
}
});
}
}
The micrometer DSL lets you increment counters and record timers directly in the route definition without writing processor boilerplate:
from("direct:processPayment")
.routeId("payment-processor")
// Increment a counter for every payment attempt
.to("micrometer:counter:payment.attempts?increment=1")
.to("direct:callPaymentGateway")
.choice()
.when(header("paymentStatus").isEqualTo("SUCCESS"))
// Counter with a tag from a header
.to("micrometer:counter:payment.results?increment=1&tags=result=success")
.otherwise()
.to("micrometer:counter:payment.results?increment=1&tags=result=failure")
.end()
// Record processing time as a distribution summary
.to("micrometer:summary:payment.amount?value=${body.amount}");
The YAML below shows the complete configuration for this feature. Adjust the values to match your environment.
# Prometheus scrape config
scrape_configs:
- job_name: camel-integration
static_configs:
- targets: ["order-service:8080"]
metrics_path: /actuator/prometheus
scrape_interval: 15s
# Prometheus alert — high failure rate on a Camel route
groups:
- name: camel-routes
rules:
- alert: CamelRouteHighFailureRate
expr: |
rate(camel_exchanges_failed_total[5m])
/
rate(camel_exchanges_total[5m]) > 0.05
for: 2m
labels:
severity: warning
annotations:
summary: "Camel route {{ $labels.routeId }} failure rate above 5%"
- alert: CamelRouteExchangeBacklog
expr: camel_exchanges_inflight > 500
for: 1m
labels:
severity: critical
annotations:
summary: "Camel route {{ $labels.routeId }} has {{ $value }} in-flight exchanges"
The PromQL queries below can be pasted directly into Grafana or the Prometheus expression browser.
# Exchange throughput per route (exchanges per second)
rate(camel_exchanges_total{application="order-service"}[1m])
# Error rate per route
rate(camel_exchanges_failed_total[5m])
/
rate(camel_exchanges_total[5m])
# Average processing time per route (seconds)
rate(camel_exchange_event_notifier_seconds_sum[5m])
/
rate(camel_exchange_event_notifier_seconds_count[5m])
# In-flight exchanges (current backlog)
camel_exchanges_inflight{application="order-service"}
# Custom metric — high-value order rate
rate(order_high_value_total[1m])
Add camel-opentelemetry-starter to automatically propagate trace context across all Camel endpoints — HTTP, Kafka, database, and between routes.
# application.yml — OpenTelemetry config
management:
tracing:
sampling:
probability: 1.0 # sample 100% in dev; use 0.1 in production
spring:
application:
name: order-integration-service
# Send traces to Zipkin or Grafana Tempo
otel:
exporter:
otlp:
endpoint: http://tempo:4317
// Camel automatically creates spans for each route and propagates
// W3C traceparent headers across HTTP calls. No code changes needed.
// Optionally add custom span attributes in a processor:
from("direct:enrichOrder")
.process(exchange -> {
Span span = Span.current();
span.setAttribute("order.id", exchange.getIn().getHeader("orderId", String.class));
span.setAttribute("order.amount", exchange.getIn().getBody(Order.class).getAmount().toString());
})
.to("http:enrichment-service/api/enrich");
The YAML below shows the complete configuration for this feature. Adjust the values to match your environment.
# application.yml — enable JMX for Camel management
camel:
springboot:
jmx-enabled: true
// Programmatic route management via CamelContext
@Service
public class RouteManagementService {
private final CamelContext camelContext;
// Suspend a route (stop consuming, in-flight exchanges complete)
public void suspendRoute(String routeId) throws Exception {
camelContext.getRouteController().suspendRoute(routeId);
}
// Resume a suspended route
public void resumeRoute(String routeId) throws Exception {
camelContext.getRouteController().resumeRoute(routeId);
}
// Get route statistics
public ManagedRouteMBean getRouteStats(String routeId) throws Exception {
return camelContext.getExtension(ManagedCamelContext.class)
.getManagedRoute(routeId, ManagedRouteMBean.class);
}
}