What is the correct way to add custom Prometheus metrics to a client library? - spring-boot

We have recently started monitoring our springboot apps with the micrometer prometheus integration. For the most part it works great out of the box; however, we have a client lib which wraps an http client for communicating with one of our apis that does NOT use Spring components, and is therefore excluded from the http_client_requests_* metric set.
The solution is obviously a #Timer annotation to manually add those custom metrics, and since our client api lib only exposes two methods, it would be ideal to just annotate these methods instead of having to add a timer anywhere I make a call with the lib in my app. The problem is, all of the setup instructions I find assume you're adding the integration to a server app instead of a lib, and I'm having trouble getting it to work.
I first tried adding the actuator and micrometer prometheus dependencies using compileOnly and runtimeOnly to hopefully not collide with the same dependencies being imported into my app, but even when that doesnt work and I change the imports to 'implementation' I get the 'No bean found with type of MeterRegistry' error other people have reported when I try to expose the TimedAspect bean like so:
#Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
Even if I got this to work, my thinking is I'd run into issues again with the
management.endpoints.web.exposure.include=health,info,prometheus
configuration the tutorials say is necessary to enable metrics collection, since my app already does this. So, before I get much deeper in attempting this approach I'd like to ask: Is there a better way to accomplish what I'm trying to do?

Related

Spring Beans Dependency Inyection with different configurations

I have the following doubt, probably a very basic one, that I have already managed to work out but I would like to listen if there is a different approach or actually if I am getting something wrong.
Background
I have an implementation with Springboot with a classic layered approach using Spring StereoTypes and wiring all up using Field DI (yes... I am aware it is not the best approach)
Service -> Repository -> (Something else)
In my case (something else) is a third party Rest API which I am calling using a RestTemplate with a specific configuration.The current solution has many services and repositories to deal with each of the Third Party domain entities. All of them using the same RestTemplate bean. The bean is inyected at the repository level.
Problem
So now I have been told from the Third Party System that depending on which business scenario my local services are executing, repositories need to use one of two different users, therefore, I assume that a different restTemplate config needs to be added. At first glance it drives me to move even higher the decision of which restTemplate to use. At Service level, not at the repo level. So I would need to have, lets say, a service A under a specific context whose dependencies (the repository) will need to have a specific template, and the same service A given another context, with a different dependency config.
Approach
The approach that I took is to have a configuration class where I generate different versions of the same service with different dependencies, in particular, their repositories using a specific template. Github Example
This approach seems like odd to me because up till now I have never had to do something like this ...and leaves me with the doubt if something different can be done to achive the same.
Another approach would be to inject both RestTemplates in the base repository and with an extra parameter to decide which to use in each method that it is being use at service level and repo level. Which I dislike.

How to capture metrics for REST end points via micrometer libraray

I am working on component that is based on spring framework. We have not yet moved to spring boot.
My requirement is to capture metrics(JVM/http/disk space) for my component which runs on an application server.
I came across micrometer library which can be utilized to capture such metrics and it can be integrated very well with Promotheus.
What I did was that I added the below dependency
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.7.5</version>
</dependency>
After adding the dependency I exposed a rest end point and added some simple logic to pull the metrics. Doing that I was able to fetch some basic JVM metrics. I referred the below link for this which explains how to capture metrics.
(https://micrometer.io/docs/ref/jvm)
However in addition to JVM metrics I also want to capture http request metrics(eg. the no of requests, time taken on the http calls to the rest services).
In my application there are quite many rest endpoints. Is there any way to do that. I was not able find any good documentation on that.
Any help would be highly appreciated.
Thanks
Sachin
As you said, Spring Boot does this out of the box so if you can move there, you don't need to do anything.
In order to instrument your web endpoints you can do a few things:
You can create a Filter and instrument all of your calls there.
This is what Spring Boot does, you can take a look/copy WebMvcMetricsFilter
You can add #Timer for your controllers and set-up TimedAspect
You can manually instrument your controllers see the docs
After following the above suggestions I was actually able to see my http metrics
I Simply created a configuration class annotated with #EnableAspectJAutoProxy and defined a bean inside the class as below
#Bean
public TimedAspect timedAspect() {
return new TimedAspect(registry);
}
And then added the #Timed annotation on my REST api POST methods and then I was able to see the statistics in Prometheus dashboard.
This really works!

Spring Boot: Extend/Edit Apache HttpClientBuilder with different configurations?

I am having an architectural issue with the Apache HttpComponents HttpClient.
We have a system where we have several different remote endpoints that we want to contact, and each have some different configurations like ssl, basic auth, et cetera.
I am using Spring Boot and Cloud Sleuth from which I get a HttpClientBuilder that gives me tracing and other things. I want to re-use that HttpClientBuilder but on-top of that add my own specific configurations, for each unique endpoint.
The problem though is that the HttpCientBuilder is not immutable with withXYZ() methods, nor is there a copy or clone method on the builder, so I can't copy the original and change just my specific changes there without altering the base HttpClientBuilder and get into conflicts with others that use the same instance of the builder. Be it racing conditions between threads or conflicting configurations between the different endpoints.
One place in the Spring Boot project where I have seen them seemingly wanting to do something similar is in HttpClientConfiguration of Spring Cloud Commons where it creates an own ApacheHttpClientFactory which takes the original autowired HttpClientBuilder and then sets disableContentCompression(), disableCookieManagement() and useSystemProperties() -- but it seemingly does it to the original instance of the HttpClientBuilder which just seems completely wrong to me. It will alter how all the built HttpClient works, and not just the one they will later be using in their Ribbon code in HttpClientRibbonConfiguration of Spring Cloud Netflix Ribbon. A potential bug in hiding? To me it seems like it, since it highly depends on calling order.
Does anyone have any ideas how something like this should be solved?
The easy alternative that I could do is to just not try and build upon the given HttpClientBuilder from Sleuth, but instead build a completely new one from the ground-up every time I need one, and check if a HttpTracing bean is available and use TracingHttpCientBuilder instead of HttpClientBuilder in that case, but this seems counter-intuitive.
I ran into the exact same problem. However, I had the option of defining my own HttpClientBuilder bean. I am not sure you are in the same position?
But by making the bean scope "prototype" a new bean instance is created every time it is injected somewhere. Then I could safely modify the HttpClientBuilder after injection.
#Bean
#Scope("prototype")
public HttpClientBuilder tracingHttpClientBuilder(..) {
...
}

Programmatically configure Spring Boot app

what's the easiest way to get the spring boot goodness but not try to autoconfigure all the things? For instance, to only run flyway with our already configured properties (some loaded via Consul + Spring Cloud), I was hoping I could do something like:
#Configuration
#Import({DataSourceAutoConfiguration.class, FlywayAutoConfiguration.class})
public class FlywaySetup {}
and have the main method just call SpringApplication.run(FlywaySetup.class)
The problem with this is it picks up all the Component Scan / crazy long list of other dependencies. Any way to specifically configure the dependencies (but still get the nicities of the framework)
If you run this app, it shouldn't use component scan at all. There's nothing that triggers component scan in spring boot besides #ComponentScan (that's available on #SpringBootApplication).
It would help if you could provide more accurate details rather than "crazy long list of other dependencies.". Running that FlywaySetup should only load those two configuration classes (important: these are not handled as auto-configuration anymore). If you have component scan, there's something else you're not showing.
You can exclude auto-configurations you don't need.
You may want to take a look at this SO answer to explore mechanism how to do that.

How to inject dependencies in Gradle Plugin in Gradle recommended way?

I am writing a custom plugin and to test it, I want to inject mock implementations. It is not just for testing but from API perspective too, I want to inject different implementations depending on the context. I am currently using Gradle 2.6 and I understand that it supports some form of Dependency Injection. I do not want to use Spring/Guice/HK2 since Gradle itself supports it. However, I am not able to find any information how to inject dependencies using Gradle 2.6 APIs.
For eg:
class CustomTask extends DefaultTask {
private SomeInterface interface
#Inject
CustomTask(SomeInterface interface) {}
#TaskAction
public void executeTask() {
interface.executeSomething()
}
}
So, essentially, I want to figure where to define bindings for different instances of SomeInterface and the mechanism to inject it into task or anywhere else like some custom classes.
Since this question was not closed, some information might still be useful for whoever runs into it.
I do not want to use Spring/Guice/HK2 since Gradle itself supports it.
You might have already seen the relevant discussion on the gradle forum.
https://discuss.gradle.org/t/dependency-injection-in-gradle-plugins/6538
We are currently working on this. Dependency injection is already available for internal Gradle services, but I'm guess you are wanting to inject your own collaborators. Our dependency injection will support this at some point.
As usually with Gradle, we can check whatever is in the oven.
https://github.com/gradle/gradle/tree/bd4fb1c396a695d55aeba9bc37e164a488c0b882/design-docs
This design document can give you a look into what one of the core maintainers thought is a good way to approach the problem. While it is not complete, I consider it quite valuable.
Unfortunately the document (along with the complete folder) has been removed on Sep 20, 2017 with the following message:
This has turned into a graveyard for ideas. It only serves to confuse
people at this point. We have found it more productive to either
use GitHub Epics and issues for smaller design questions
use Google Docs for larger topics (e.g. native publishing)
These documents quickly go out of date once a feature is implemented.
They are not a replacement for good user and code documentation.
Many of the documents are about features that we never ended up
implementing. Having those documents still around might lock us into a
certain way of thinking about a problem. Instead we should have a
fresh look at it when we actually want to start working on it.

Resources