6.2. Monitoring a Camel Spring Boot application
After you enable the monitoring for your project, you can deploy and monitor the Camel Spring Boot application. This section uses the monitoring-micrometrics-grafana-prometheus example listed in the Camel Spring Boot Examples.
Procedure
-
Add the openshift-maven-plugin to the
pom.xmlfile of themonitoring-micrometrics-grafana-prometheusexample. In thepom.xml, add an openshift profile to allow deployment to openshift through the openshift-maven-plugin. Add the openshift-maven-plugin to the
pom.xmlfile of themonitoring-micrometrics-grafana-prometheusexample. In thepom.xml, add an openshift profile to allow deployment to openshift through theopenshift-maven-plugin.<profiles> <profile> <id>openshift</id> <build> <plugins> <plugin> <groupId>org.eclipse.jkube</groupId> <artifactId>openshift-maven-plugin</artifactId> <version>1.13.1</version> <executions> <execution> <goals> <goal>resource</goal> <goal>build</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles>Add the Prometheus support. In order to add the Prometheus support to your Camel application, expose the Prometheus statistics on an actuator endpoint.
-
Edit your
src/main/resources/application.propertiesfile. -
Add a
management.endpoints.web.exposure.includeentry if it doesn’t exist. Add prometheus, metrics, and health to the
management.endpoints.web.exposure.includeentry:# expose actuator endpoint via HTTP management.endpoints.web.exposure.include=mappings,metrics,health,shutdown,jolokia,prometheus
-
Edit your
Add the following to the
<dependencies/>section of your pom.xml to add some starter support to your application.<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.1.8</version> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> <version>1.13.6</version> </dependency> <dependency> <groupId>org.jolokia</groupId> <artifactId>jolokia-server-core</artifactId> <version>2.2.5.redhat-00001</version> </dependency> <dependency> <groupId>io.prometheus.jmx</groupId> <artifactId>collector</artifactId> <version>1.0.1</version> </dependency>Create the file
config/prometheus_exporter_config.yml:startDelaySecs: 5 ssl: false blacklistObjectNames: ["java.lang:*"] rules: # Context level - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>ExchangesCompleted' name: org.apache.camel.ExchangesCompleted help: Exchanges Completed type: COUNTER labels: context: $1 type: context - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>ExchangesFailed' name: org.apache.camel.ExchangesFailed help: Exchanges Failed type: COUNTER labels: context: $1 type: context - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>ExchangesInflight' name: org.apache.camel.ExchangesInflight help: Exchanges Inflight type: GAUGE labels: context: $1 type: context - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>ExchangesTotal' name: org.apache.camel.ExchangesTotal help: Exchanges Total type: COUNTER labels: context: $1 type: context - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>FailuresHandled' name: org.apache.camel.FailuresHandled help: Failures Handled labels: context: $1 type: context type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>ExternalRedeliveries' name: org.apache.camel.ExternalRedeliveries help: External Redeliveries labels: context: $1 type: context type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>MaxProcessingTime' name: org.apache.camel.MaxProcessingTime help: Maximum Processing Time labels: context: $1 type: context type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>MeanProcessingTime' name: org.apache.camel.MeanProcessingTime help: Mean Processing Time labels: context: $1 type: context type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>MinProcessingTime' name: org.apache.camel.MinProcessingTime help: Minimum Processing Time labels: context: $1 type: context type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>LastProcessingTime' name: org.apache.camel.LastProcessingTime help: Last Processing Time labels: context: $1 type: context type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>DeltaProcessingTime' name: org.apache.camel.DeltaProcessingTime help: Delta Processing Time labels: context: $1 type: context type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>Redeliveries' name: org.apache.camel.Redeliveries help: Redeliveries labels: context: $1 type: context type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=context, name=([^,]+)><>TotalProcessingTime' name: org.apache.camel.TotalProcessingTime help: Total Processing Time labels: context: $1 type: context type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=consumers, name=([^,]+)><>InflightExchanges' name: org.apache.camel.InflightExchanges help: Inflight Exchanges labels: context: $1 type: context type: GAUGE # Route level - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>ExchangesCompleted' name: org.apache.camel.ExchangesCompleted help: Exchanges Completed type: COUNTER labels: context: $1 route: $2 type: routes - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>ExchangesFailed' name: org.apache.camel.ExchangesFailed help: Exchanges Failed type: COUNTER labels: context: $1 route: $2 type: routes - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>ExchangesInflight' name: org.apache.camel.ExchangesInflight help: Exchanges Inflight type: GAUGE labels: context: $1 route: $2 type: routes - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>ExchangesTotal' name: org.apache.camel.ExchangesTotal help: Exchanges Total type: COUNTER labels: context: $1 route: $2 type: routes - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>FailuresHandled' name: org.apache.camel.FailuresHandled help: Failures Handled labels: context: $1 route: $2 type: routes type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>ExternalRedeliveries' name: org.apache.camel.ExternalRedeliveries help: External Redeliveries labels: context: $1 route: $2 type: routes type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>MaxProcessingTime' name: org.apache.camel.MaxProcessingTime help: Maximum Processing Time labels: context: $1 route: $2 type: routes type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>MeanProcessingTime' name: org.apache.camel.MeanProcessingTime help: Mean Processing Time labels: context: $1 route: $2 type: routes type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>MinProcessingTime' name: org.apache.camel.MinProcessingTime help: Minimum Processing Time labels: context: $1 route: $2 type: routes type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>LastProcessingTime' name: org.apache.camel.LastProcessingTime help: Last Processing Time labels: context: $1 route: $2 type: routes type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>DeltaProcessingTime' name: org.apache.camel.DeltaProcessingTime help: Delta Processing Time labels: context: $1 route: $2 type: routes type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>Redeliveries' name: org.apache.camel.Redeliveries help: Redeliveries labels: context: $1 route: $2 type: routes type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>TotalProcessingTime' name: org.apache.camel.TotalProcessingTime help: Total Processing Time labels: context: $1 route: $2 type: routes type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=routes, name=([^,]+)><>InflightExchanges' name: org.apache.camel.InflightExchanges help: Inflight Exchanges labels: context: $1 route: $2 type: routes type: GAUGE # Processor level - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>ExchangesCompleted' name: org.apache.camel.ExchangesCompleted help: Exchanges Completed type: COUNTER labels: context: $1 processor: $2 type: processors - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>ExchangesFailed' name: org.apache.camel.ExchangesFailed help: Exchanges Failed type: COUNTER labels: context: $1 processor: $2 type: processors - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>ExchangesInflight' name: org.apache.camel.ExchangesInflight help: Exchanges Inflight type: GAUGE labels: context: $1 processor: $2 type: processors - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>ExchangesTotal' name: org.apache.camel.ExchangesTotal help: Exchanges Total type: COUNTER labels: context: $1 processor: $2 type: processors - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>FailuresHandled' name: org.apache.camel.FailuresHandled help: Failures Handled labels: context: $1 processor: $2 type: processors type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>ExternalRedeliveries' name: org.apache.camel.ExternalRedeliveries help: External Redeliveries labels: context: $1 processor: $2 type: processors type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>MaxProcessingTime' name: org.apache.camel.MaxProcessingTime help: Maximum Processing Time labels: context: $1 processor: $2 type: processors type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>MeanProcessingTime' name: org.apache.camel.MeanProcessingTime help: Mean Processing Time labels: context: $1 processor: $2 type: processors type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>MinProcessingTime' name: org.apache.camel.MinProcessingTime help: Minimum Processing Time labels: context: $1 processor: $2 type: processors type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>LastProcessingTime' name: org.apache.camel.LastProcessingTime help: Last Processing Time labels: context: $1 processor: $2 type: processors type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>DeltaProcessingTime' name: org.apache.camel.DeltaProcessingTime help: Delta Processing Time labels: context: $1 processor: $2 type: processors type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>Redeliveries' name: org.apache.camel.Redeliveries help: Redeliveries labels: context: $1 processor: $2 type: processors type: COUNTER - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>TotalProcessingTime' name: org.apache.camel.TotalProcessingTime help: Total Processing Time labels: context: $1 processor: $2 type: processors type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=processors, name=([^,]+)><>InflightExchanges' name: org.apache.camel.InflightExchanges help: Inflight Exchanges labels: context: $1 processor: $2 type: processors type: COUNTER # Consumers - pattern: 'org.apache.camel<context=([^,]+), type=consumers, name=([^,]+)><>InflightExchanges' name: org.apache.camel.InflightExchanges help: Inflight Exchanges labels: context: $1 consumer: $2 type: consumers type: GAUGE # Services - pattern: 'org.apache.camel<context=([^,]+), type=services, name=([^,]+)><>MaxDuration' name: org.apache.camel.MaxDuration help: Maximum Duration labels: context: $1 service: $2 type: services type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=services, name=([^,]+)><>MeanDuration' name: org.apache.camel.MeanDuration help: Mean Duration labels: context: $1 service: $2 type: services type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=services, name=([^,]+)><>MinDuration' name: org.apache.camel.MinDuration help: Minimum Duration labels: context: $1 service: $2 type: services type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=services, name=([^,]+)><>TotalDuration' name: org.apache.camel.TotalDuration help: Total Duration labels: context: $1 service: $2 type: services type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=services, name=([^,]+)><>ThreadsBlocked' name: org.apache.camel.ThreadsBlocked help: Threads Blocked labels: context: $1 service: $2 type: services type: GAUGE - pattern: 'org.apache.camel<context=([^,]+), type=services, name=([^,]+)><>ThreadsInterrupted' name: org.apache.camel.ThreadsInterrupted help: Threads Interrupted labels: context: $1 service: $2 type: services type: GAUGE - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>NumLogicalRuntimeFaults' name: org.apache.cxf.NumLogicalRuntimeFaults help: Number of logical runtime faults type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+)><>NumLogicalRuntimeFaults' name: org.apache.cxf.NumLogicalRuntimeFaults help: Number of logical runtime faults type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>AvgResponseTime' name: org.apache.cxf.AvgResponseTime help: Average Response Time type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+)><>AvgResponseTime' name: org.apache.cxf.AvgResponseTime help: Average Response Time type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>NumInvocations' name: org.apache.cxf.NumInvocations help: Number of invocations type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+)><>NumInvocations' name: org.apache.cxf.NumInvocations help: Number of invocations type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>MaxResponseTime' name: org.apache.cxf.MaxResponseTime help: Maximum Response Time type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+)><>MaxResponseTime' name: org.apache.cxf.MaxResponseTime help: Maximum Response Time type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>MinResponseTime' name: org.apache.cxf.MinResponseTime help: Minimum Response Time type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>MinResponseTime' name: org.apache.cxf.MinResponseTime help: Minimum Response Time type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>TotalHandlingTime' name: org.apache.cxf.TotalHandlingTime help: Total Handling Time type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+)><>TotalHandlingTime' name: org.apache.cxf.TotalHandlingTime help: Total Handling Time type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>NumRuntimeFaults' name: org.apache.cxf.NumRuntimeFaults help: Number of runtime faults type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+)><>NumRuntimeFaults' name: org.apache.cxf.NumRuntimeFaults help: Number of runtime faults type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>NumUnCheckedApplicationFaults' name: org.apache.cxf.NumUnCheckedApplicationFaults help: Number of unchecked application faults type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+)><>NumUnCheckedApplicationFaults' name: org.apache.cxf.NumUnCheckedApplicationFaults help: Number of unchecked application faults type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+), operation=([^,]+)><>NumCheckedApplicationFaults' name: org.apache.cxf.NumCheckedApplicationFaults help: Number of checked application faults type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4 operation: $5 - pattern: 'org.apache.cxf<bus.id=([^,]+), type=([^,]+), service=([^,]+), port=([^,]+)><>NumCheckedApplicationFaults' name: org.apache.cxf.NumCheckedApplicationFaults help: Number of checked application faults type: GAUGE labels: bus.id: $1 type: $2 service: $3 port: $4Add the following to the
Application.javaof your Camel application.import java.io.InputStream; import io.micrometer.core.instrument.Clock; import org.apache.camel.CamelContext; import org.apache.camel.spring.boot.CamelContextConfiguration; import org.springframework.context.annotation.Bean; import org.apache.camel.component.micrometer.MicrometerConstants; import org.apache.camel.component.micrometer.eventnotifier.MicrometerExchangeEventNotifier; import org.apache.camel.component.micrometer.eventnotifier.MicrometerRouteEventNotifier; import org.apache.camel.component.micrometer.messagehistory.MicrometerMessageHistoryFactory; import org.apache.camel.component.micrometer.routepolicy.MicrometerRoutePolicyFactory;The updated
Application.javais shown below.@SpringBootApplication public class SampleCamelApplication { @Bean(name = {MicrometerConstants.METRICS_REGISTRY_NAME, "prometheusMeterRegistry"}) public PrometheusMeterRegistry prometheusMeterRegistry( PrometheusConfig prometheusConfig, CollectorRegistry collectorRegistry, Clock clock) throws MalformedObjectNameException, IOException { InputStream resource = new ClassPathResource("config/prometheus_exporter_config.yml").getInputStream(); new JmxCollector(resource).register(collectorRegistry); new BuildInfoCollector().register(collectorRegistry); return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock); } @Bean public CamelContextConfiguration camelContextConfiguration(@Autowired PrometheusMeterRegistry registry) { return new CamelContextConfiguration() { @Override public void beforeApplicationStart(CamelContext camelContext) { MicrometerRoutePolicyFactory micrometerRoutePolicyFactory = new MicrometerRoutePolicyFactory(); micrometerRoutePolicyFactory.setMeterRegistry(registry); camelContext.addRoutePolicyFactory(micrometerRoutePolicyFactory); MicrometerMessageHistoryFactory micrometerMessageHistoryFactory = new MicrometerMessageHistoryFactory(); micrometerMessageHistoryFactory.setMeterRegistry(registry); camelContext.setMessageHistoryFactory(micrometerMessageHistoryFactory); MicrometerExchangeEventNotifier micrometerExchangeEventNotifier = new MicrometerExchangeEventNotifier(); micrometerExchangeEventNotifier.setMeterRegistry(registry); camelContext.getManagementStrategy().addEventNotifier(micrometerExchangeEventNotifier); MicrometerRouteEventNotifier micrometerRouteEventNotifier = new MicrometerRouteEventNotifier(); micrometerRouteEventNotifier.setMeterRegistry(registry); camelContext.getManagementStrategy().addEventNotifier(micrometerRouteEventNotifier); } @Override public void afterApplicationStart(CamelContext camelContext) { } }; }Deploy the application to OpenShift.
mvn -Popenshift oc:deployVerify if your application is deployed.
oc get pods -n myapp NAME READY STATUS RESTARTS AGE camel-example-spring-boot-xml-2-deploy 0/1 Completed 0 13m camel-example-spring-boot-xml-2-x78rk 1/1 Running 0 13m camel-example-spring-boot-xml-s2i-2-build 0/1 Completed 0 14mAdd the Service Monitor for this application so that Openshift’s prometheus instance can start scraping from the / actuator/prometheus endpoint.
Create the following YAML manifest for a Service monitor. In this example, the file is named as
servicemonitor.yaml.apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: labels: k8s-app: csb-demo-monitor name: csb-demo-monitor spec: endpoints: - interval: 30s port: http scheme: http path: /actuator/prometheus selector: matchLabels: app: camel-example-spring-boot-xmlAdd a Service Monitor for this application.
oc apply -f servicemonitor.yml servicemonitor.monitoring.coreos.com/csb-demo-monitor "myapp" created
Verify that the service monitor was successfully deployed.
oc get servicemonitor NAME AGE csb-demo-monitor 9m17s-
Verify that you can see the service monitor in the list of scrape targets. In the Administrator view, navigate to Observe
Targets. You can find csb-demo-monitorwithin the list of scrape targets. -
Wait about ten minutes after deploying the servicemonitor. Then navigate to the Observe
Metrics in the Developer view. Select Custom query in the drop-down menu and type camelto view the Camel metrics that are exposed through the /actuator/prometheus endpoint.
Red Hat does not offer support for installing and configuring Prometheus and Grafana on non-OCP environments.