Send Apache Camel Actuator Metrics to Prometheus - java

I am trying to forward/add the Actuator Camel metrics from /actuator/camelroutes (route metrics like number of exchanges/transactions) to the Prometheus Actuator endpoint. Is there a way for me to configure Camel to add those metrics to the PrometheusMeterRegistry?
I have tried adding:
camel.component.metrics.metric-registry=io.micrometer.prometheus.PrometheusMeterRegistry
in my application.properties according to the documentation here: https://camel.apache.org/components/latest/metrics-component.html
But still nothing relating to Apache Camel is displayed in actuator/prometheus
Here are the dependencies I am using with Spring Boot 2.1.9 and Apache Camel 2.24.2:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-metrics-starter</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Got the Camel Routes metrics working in the /actuator/prometheus endpoint.
Use the camel-micrometer-starter dependency as stated by #claus-ibsen 's comment.
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-metrics-starter</artifactId>
</dependency>
Set the following in your properties file:
camel.component.metrics.metric-registry=prometheusMeterRegistry
Then add set the Camel Context to use the MicrometerRouterPolicyFactory and MicrometerMessageHistoryFactory. Code seen below is places in a Configuration class:
#Configuration
public class AppConfig {
#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) {
}
};
}
}
You need to trigger an exchange in a route for the metrics to appear in /actuator/prometheus.
Here are the metrics made available to Prometheus:
CamelMessageHistory_seconds_count
CamelMessageHistory_seconds_max
CamelRoutePolicy_seconds_max
CamelRoutePolicy_seconds_count
CamelRoutePolicy_seconds_sum
You can use the JMX Exporter jar for Prometheus to get the more detailed metrics from the JMX of Camel. I wanted to avoid this approach as it would mean that for each Camel Spring Boot App I have would use 2 ports; 1 for the JMX Metrics and 1 for the Actuator Metrics.

There is a camel-micrometer-starter dependency you should use instead that integrates with micrometer. And then you can use the micrometer route policy from that dependency to let it monitor all your routes. See the docs at: https://camel.apache.org/components/2.x/micrometer-component.html

I can see the metrics by keeping these dependencies intact
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-management</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-metrics</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-micrometer-starter</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Why dont I see the actual process and bean names rather than like process3, bean1 etc ??
CamelMessageHistory_seconds_sum{camelContext="AppName",nodeId="process3",routeId="AppNameRoute",serviceName="MicrometerMessageHistoryService",} 0.041466
CamelMessageHistory_seconds_count{camelContext="AppName",nodeId="bean1",routeId="AppNameRoute",serviceName="MicrometerMessageHistoryService",} 100.0
CamelMessageHistory_seconds_sum{camelContext="AppName",nodeId="bean1",routeId="AppNameRoute",serviceName="MicrometerMessageHistoryService",} 4.8417576

Related

How to specify GZip properties in Spring boot 2 application

I have spring boot 2 application with REST API clients. There is a API to download large byte array (around 85MB), so I willing to compress it using GZip encoding. Added following properties to application.properties file
server.compression.enabled=true
server.compression.min-response-size=1024
server.compression.mime-types=application/octet-stream
Default compression reduce file size but it increase processing time rapidly. I saw there are compression levels in GZip encoding from 0-9.
How I set compression level in application.properties file.
Resolve my issue by changing embedded server to jetty.
First exclude embedded tomcat and add jetty dependency in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Then add Custom JettyServletWebServerFactory as follows
#Configuration
public class GZipConfig {
#Bean
public JettyServletWebServerFactory jettyServletWebServerFactory() {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.addServerCustomizers((Server server) -> {
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setInflateBufferSize(1);
gzipHandler.setHandler(server.getHandler());
gzipHandler.setIncludedMethods("GET", "POST", "DELETE", "PUT");
gzipHandler.setCompressionLevel(Deflater.BEST_SPEED);
HandlerCollection handlerCollection = new HandlerCollection(gzipHandler);
server.setHandler(handlerCollection);
});
return factory;
}
}
Here we can add compression level.
Thanks

Swagger 2 Issue spring Boot

I'm facing issue with Swagger Integration in Spring Boot. Have a look at the code and error snippet.
------------------POM--------------------
<properties>
<java.version>1.8</java.version>
<swagger.version>2.9.2</swagger.version>
</properties>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>${swagger.version}</version>
</dependency>
-----------------App class--------------
#SpringBootApplication
#EnableSwagger2
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ServletPocProducerApplication.class, args);
}
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
Stack Trace
org.springframework.context.ApplicationContextException: Failed to start bean
'documentationPluginsBootstrapper'; nested exception is
java.lang.NullPointerException: Cannot invoke
"org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.toString()"
because the return value of
"springfox.documentation.spi.service.contexts.Orderings.patternsCondition(springfox.docume
ntation.RequestHandler)" is null
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.13.jar:5.3.13]
How do I fix this??
I solved it by adding "spring.mvc.pathmatch.matching-strategy=ant-path-matcher" in application.properties.
For a long time I have tried to solve this problem and solution for this is:
a) adding this to application.properties:
spring.mvc.pathmatch.matching-strategy=ant-path-matcher
b) adding this to application.yaml(or application.yml):
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
I know this does not solve your problem directly, but consider moving to springdoc. Springfox is so buggy at this point that is a pain to use. I've moved to springdoc 2 years ago because of its Spring WebFlux support and I am very happy about it. Additionally, it also supports Kotlin Coroutines, which I am not sure Springfox does.
If you decide to migrate, springdoc even has a migration guide.
For the integration between spring-boot and swagger-ui, add the library to the list of your project dependencies (No additional configuration is needed):
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.12</version>
</dependency>
The Swagger UI page will then be available at
http://server:port/context-path/swagger-ui.html and the OpenAPI
description will be available at the following url for json format:
http://server:port/context-path/v3/api-docs
server: The server name or IP
port: The server port
context-path: The context path of the application
Adding this "spring.mvc.pathmatch.matching-strategy=ant-path-matcher" to your application.properties file solves the problem.
It's what i used and i saved me alot of trouble.
My suggestion is when you are using spring-boot then it is better to use spring boot dependency for swagger. So, spring-boot will take care of your default settings.
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>...</version>
</dependency>

How to expose swagger UI interface with jetty server and camel

I am doing a camel project with Jetty server using Springboot, I must expose the apis swagger-ui. I have already generated the swager in json format and it can be consulted at localhost:8080/swagger. Using swagger-ui webjars I am trying to see the graphic interface of swagger but this is not generated.
Im using this maven dependencies:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-swagger-java-starter</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>0.36</version>
</dependency>
it is suppose that when using webjars the swagger-ui can be consulted in the path /webjars/swagger-ui/index.html, but i get:
Problem accessing /webjars/swagger-ui/index.html. Reason:Not Found
I tried to define a camel route like this: but doesnt work.
rest("/swagger")
.produces("text/html")
.get("/index.html")
.responseMessage().code(200).message("Swagger UI").endResponseMessage()
.to("direct://get/swagger/ui/path");
from("direct://get/swagger/ui/path")
.routeId("SwaggerUI")
.setBody().simple("resource:classpath:META-INF/resources/webjars/swagger-ui/3.1.4/index.html");
I was using this example:
https://medium.com/#bszeti/swagger-with-spring-boot-and-camel-ac59cca9556e
but I use Jetty as rest component
restConfiguration().component("jettty").port(8080).bindingMode(RestBindingMode.json)
.skipBindingOnErrorCode(false)
How can I expose the swagger Ui Interface?
I hope someone can help me, thank you very much

use spring cloud gateway with oauth2

i face a problem when i using spring cloud gateway
is if any dependency call spring-boot-starter-tomcat directly or recursively
it will not work because it will start the embedded tomcat server not the netty server that spring cloud gateway use
i started to solve this problem by excluding this dependency
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
the spring cloud gateway worked successfully
but sometimes i want to use spring-cloud-starter-oauth2 to use #EnableOAuth2Sso
i start to use
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
at that time i face the big issue that throw exception saying
Caused by: java.lang.IllegalStateException: Failed to introspect annotated methods on class org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration
......
Caused by: java.lang.NoClassDefFoundError: javax/servlet/Filter
As you've seen, the Spring cloud gateway uses the reactive model and is based on netty rather than tomcat. The reactive change is a major shift and currently isn't supported by Spring Security but work is in progress on it and you can track it at https://github.com/spring-cloud/spring-cloud-gateway/issues/179
Use the following dependencies (I copied from my build.gradle)
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
}
Code your gateway app minimally as follows
#SpringBootApplication
public class App {
#Bean
public ForwardedHeaderTransformer forwardedHeaderTransformer() {
return new ForwardedHeaderTransformer();
}
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Configure in application.yml
spring:
security:
oauth2:
client:
registration:
google:
client-id: XXX
client-secret: YYY
I am actively building my stack that uses OAuth2 with Docker Swarm Discovery https://github.com/trajano/spring-cloud-demo.git so you can see how it would work in action.
spring boot 2.1 with spring security 5 have resolve this problem
see this example

Spring Boot and ActiveMQ: Ignores broker-url and uses default localhost:61616

I'm using Spring Boot and ActiveMQ. In application.properties I set the url for activemq like this:
spring.activemq.broker-url=vm://localhost?broker.persistent=false
As you can see I'm using an embedded broker (dependency added in pom).
This is my application class:
#SpringBootApplication
#EntityScan(
basePackageClasses = {ServiceApplication.class, Jsr310JpaConverters.class}
)
#EnableAutoConfiguration
#ServletComponentScan
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
These are the activemq related dependencies in the pom:
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-camel</artifactId>
<version>5.14.5</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>5.14.5</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
<version>5.14.5</version>
</dependency>
I have a single application.properties, I don't have different profiles.
But when I run the app, I get this log:
[ActiveMQ Task-1] o.a.a.t.failover.FailoverTransport : Failed to connect to [tcp://localhost:61616] after: 10 attempt(s) continuing to retry.
It's trying to connect to tcp://localhost:61616 even though that's not the url I defined.
I tried removing #EnableAutoConfiguration but still the same issue.
How can I solve this?
Your ActiveMQ client is not aware of spring.activemq.broker-url since this property is used to configure spring-boot-starter-activemq.If you do not have this starter - you configure nothing with this property.
I would suggest you to go through the following resources to have a better understanding of how to set up spring-boot-starter-activemq in your project:
https://spring.io/guides/gs/messaging-jms/
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-messaging.html
Hope it helps!

Categories