Contents

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.

MetricTypeDescription
camel.exchanges.totalCounterTotal exchanges processed per route
camel.exchanges.succeeded.totalCounterSuccessful exchanges per route
camel.exchanges.failed.totalCounterFailed exchanges per route
camel.exchanges.inflightGaugeCurrently in-flight exchanges
camel.exchange.event.notifierTimerExchange processing time per route
camel.route.policyTimerRoute 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); } }