metrics for my api powered by jersey - jersey

I try to instrumente my Jersey webservice with Metrics
http://metrics.codahale.com/manual/jersey/
I don't understand how to use this library?
Do I need to add something in my web.xml file?
Thanks

To instrument your Jersey web service, you must add the metrics-jersey module to your application, it contains a #Provider implementation class (make sure Jersey find it) that allow you to instrument your Jersey resources methods annotated with #Timed, Metered and ExceptionMetered.
By default, Metrics reports through JMX, so you can use JConsole to validate your instrumentations.
Like Alex wrote, there are others reporting options but it requires additional configuration or code (call enable method on the Reporter).
For example you can fetch reports in JSON by HTTP, or have you webservice send reports to a monitoring server such as Graphite.

As I can see, you just need to include metrics lib to the build path. On web-services methods you just use annotation #Timed.
To see the reports, you must enable the reporting style you like - reporters

Drop your linen and start your grin'n. I got this working!
Hook up the servlet. You need a generic spot to make and store the metrics. Build one of these for both MetricsRegistry and HealthCheckRegistry :
public class MetricsServletContextListener extends MetricsServlet.ContextListener {
public static final MetricRegistry METRIC_REGISTRY = new MetricRegistry();
#Override
protected MetricRegistry getMetricRegistry() {
return METRIC_REGISTRY;
}
}
Set the servlet context with the data in some startup area:
sc.getServletContext().setAttribute(
"com.codahale.metrics.servlets.HealthCheckServlet.registry",
healthChecks
);
sc.getServletContext().setAttribute(
"com.codahale.metrics.servlets.MetricsServlet.registry",
MetricsServletContextListener.METRIC_REGISTRY
);
Url is: http://blah/blah/metrics/metrics?pretty=true
Create one of these guys. This hooks up the metrics to Jersey:
#Provider
public class TmaticInstrumentedResourceMethodDispatchAdapterWrapper implements ResourceMethodDispatchAdapter {
private InstrumentedResourceMethodDispatchAdapter adapter = null;
public TmaticInstrumentedResourceMethodDispatchAdapterWrapper() {
adapter = new InstrumentedResourceMethodDispatchAdapter(MetricsServletContextListener.METRIC_REGISTRY);
}
#Override
public ResourceMethodDispatchProvider adapt(ResourceMethodDispatchProvider provider) {
return adapter.adapt(provider);
}
}
Tell jersey about it. Since it uses the #Provider annotation it must be in an area that can scan for it. I had to add mine to the web.xml here but you might not have to:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>blah.endpoint,blah.utils</param-value>
</init-param>
And add the annotatation #Timed to your jersey endpoint.

Related

Spring boot actuator 2 metrics from custom function

I am in the spring-boot-actuator world mow...
How can I add my own metrics coming from a custom function from my #Service class?
I would expect to have something like
meterRegistry.registerNewGauge(
"animals_count",
"cats",
animalCounterService::countCatsFromDatabase
);
currently i can only find easy metrics like
meterRegistry.counter("animals_count").increment();
but that doesn't help much when I have to aggregate things like database entries. I need a more flexible one.
I also found something like MeterBinder.bindTo but that didn't worked. No error, nothing in metrics.
I am searching now for months without any success.
thanks
I'm assuming you're using Micrometer for metrics, right?
If so, you can create a gauge and bind it to any object that provides a method that returns double like this:
#Service
public class MyService {
...
public double calculateValueForGauge() {...}
}
MyService service = ...// get from spring
MeterRegistry registry = ... // get from spring
// here is how you can create a gauge and bind it to an arbitrary method of your service
Gauge.builder("some.name.goes.here, service, (service) -> service.calculateValueForGauge())
.register(registry);
For example you can place the code of gauge registration to the listener that will be called when the application context is started:
#EventListener
public void onApplicationStarted(ApplicationReadyEvent event) {
// register gauges here
}

How to have dynamic base URL with Quarkus MicroProfile Rest Client?

Quarkus using Rest Client, explains how to use the MicroProfile REST Client. For Base URL application.properties can be used.
org.acme.restclient.CountriesService/mp-rest/url=https://restcountries.eu/rest #
With above approach, cant have dynamic base URL.
Able to achieve it by using RestClientBuilder as explained in MicroProfile Rest Client. Downside of this approach is not having auto-negotiation capability.
SimpleGetApi simpleGetApi = RestClientBuilder.newBuilder().baseUri(getApplicationUri()).build(SimpleGetApi.class);
Is there other or better way to achieve this? Thanks.
While it is true, that the MP Rest CLient does not allow you to set the BaseUri dynamically when you use declarative/Injected clients, there are some (albeit hacky) ways how to achieve that.
One is to use standard ClientRequestFilter which can modify the URL:
#Provider
#Slf4j
public class Filter implements ClientRequestFilter {
#Inject RequestScopeHelper helper;
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
if (helper.getUrl() != null) {
URI newUri = URI.create(requestContext.getUri().toString().replace("https://originalhost.com", helper.getUrl()));
requestContext.setUri(newUri);
}
}
}
Where RequestScopeHelper is some help class (e.g. request scoped bean) through which you can pass the dynamic url, for example:
#Inject
RequestScopeHelper helper;
#Inject
#RestClient
TestIface myApiClient;
public void callSomeAPIWithDynamicBaseUri(String dynamic) {
helper.setUrl(dynamic);
myApiClient.someMethod();
}
Second is to use MP rest client SPI, namely the RestClientListener which allows you to modify the rest clients after they are built.
For this to work, you have to set the scope of your rest client to RequestScoped so that new instance is created for each request(if you use singleton for example, then the client is only created once and your listener will only be called once). This you can do via quarkus properties:
quarkus.rest-client."com.example.MyRestIface".scope=javax.enterprise.context.RequestScoped
public class MyListener implements RestClientListener {
#Override
public void onNewClient(Class<?> serviceInterface, RestClientBuilder builder) {
String newUri = //obtain dynamic URI from somewhere e.g. again request scope bean lookup, or maybe dynamic config source (create new in-memory ConfigSource, before you invoke your rest client set the corresponding rest client url property to your dynamic value, then inside this listener use ConfigProvider.getConfig().getProperty...)
builder.baseUri(URI.create(newUri));
}
}
Don't forget to register this listener as service provider(META-INF/services/org.eclipse.microprofile.rest.client.spi.RestClientListener)
Another option is to use custom CDI producer that would produce the Rest client instances for you; then you could control all client config yourself. You can use the RestClientBase from Quarkus rest client which is exactly what Quarkus uses under the hood during deployment phase to construct client instances. You will however have to duplicate all the logic related to registration of handlers, interceptors etc.
Do keep in mind, that any of these solutions will make the debugging and problem analysis more challenging - because you will now have multiple places, where the URI is controlled(MP config/quarkus properties, env vars, your custom impl...), so you need to be careful with your approach and maybe add some explicit log messages when you override the URI manually.
MicroProfile REST Client in Quarkus does allow you to use dynamic base URL with that simple "hack" :
Just put an empty String in #Path annotations for you API interface like that :
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("")
public interface SimpleGetApi {
#Path("")
#GET
String callWithDynmamicUrl(); //it can be String or any return type you want
}
After that you are ready to call your dynamic base URL :
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import java.net.URI;
public class Example {
public static void main(String[] args) {
URI anyDynamicUrl = URI.create("http://restcountries.eu/rest/some/dynamic/path");
SimpleGetApi simpleGetApi = RestClientBuilder.newBuilder().baseUri(anyDynamicUrl)
.build(SimpleGetApi.class);
simpleGetApi.callWithDynmamicUrl();
}
}

how to Enforce request header on all spring web RestController equests

Is there an option to specify a request header once in spring web RestController instead of doing it on every request?
e.q.
#RestController("workflowController")
public class MyClass{
public Value list(#RequestHeader(USER_ID_HEADER_PARAM) String user) {
...some code
}
public Workflow create(#RequestBody Workflow workflow, #RequestHeader(USER_ID_HEADER_PARAM) String user) {
... some code
}
}
the #RequestHeader(USER_ID_HEADER_PARAM) will be repeated in every request.
is there a way to specity it in the #RestCotroller level or the class level?
Thanks
Use some kind of filter class that can be configured to wrap around your requests in your servlets based on the URL path.
Here is info about the generic Servlet API filter API:
https://www.oracle.com/technetwork/java/filters-137243.html
If you're using Spring, there's another way to do it:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#filters
https://www.baeldung.com/intercepting-filter-pattern-in-java

Configuring Spring MockMvc to use custom argument resolver before built-in ones

I have a straightforward test case. I have a controller which has a parameter of a type Spring doesn't support by default, so I wrote a custom resolver.
I create the mock mvc instance I'm using like so:
mvc = MockMvcBuilders.standaloneSetup(controller).setCustomArgumentResolvers(new GoogleOAuthUserResolver()).build();
However, Spring is also registering almost 30 other argument resolvers, one of which is general enough that it is getting used to resolve the argument before mine. How can I set or sort the resolvers so that mine is invoked first?
This worked for me without reflection:
#RequiredArgsConstructor
#Configuration
public class CustomerNumberArgumentResolverRegistration {
private final RequestMappingHandlerAdapter requestMappingHandlerAdapter;
#PostConstruct
public void prioritizeCustomArgumentResolver () {
final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(Objects.requireNonNull(requestMappingHandlerAdapter.getArgumentResolvers()));
argumentResolvers.add(0, new CustomerNumberArgumentResolver());
requestMappingHandlerAdapter.setArgumentResolvers(argumentResolvers);
}
}
The issue was that the People class the Google OAuth library I am using extends Map and the mock servlet API provides no way to manipulate the order in which the handlers are registered.
I ended up using reflection to reach into the mocks guts and remove the offending handler.

Swagger2Markup : how to group by tags when using Swagger remote endpoint from test?

I'm using the great swagger2markup plugin to generate Asciidoc documentation for my REST API as provided by Swagger. I have followed swagger2markup documentation and I am using a Spring MVC integration test to generate markup from my Springfox Swagger endpoint like this (I'm using Maven) :
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = { AppConfig.class, SwaggerConfig.class })
public class DocumentationIT {
protected MockMvc mockMvc;
#Autowired
protected WebApplicationContext webApplicationContext;
#Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("src/docs/asciidoc/apidoc/generated-snippets");
#Before
public void setUp(){
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(this.restDocumentation))
.build();
}
#Test
public void convertSwaggerToAsciiDoc() throws Exception {
this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andDo(
Swagger2MarkupResultHandler
.outputDirectory("src/docs/asciidoc/apidoc")
.withExamples("src/docs/asciidoc/apidoc/generated-snippets").build())
.andExpect(status().isOk());
}
}
Everything is working great and all my paths are in my final documentation, however paths all appear directly at the root and are not grouped by resources (i.e. by controllers), so Method 1 from Controller 1 will appear at the same level as Method 2 from Controller 2.
My output :
What I'd like :
From what I can see, when using generation from a local file like in this swagger2-markup Maven project template you can specify a property to tell swagger2markup to group your paths by tags using the config property <swagger2markup.pathsGroupedBy>TAGS</swagger2markup.pathsGroupedBy>, however there does not seem to be such configuration when using Swagger2MarkupResultHandler from a test. The only option is withMarkupLanguage() but there is no withPathsGroupedBy() method...
Am i missing something here ?
As you mentioned, there is a property of swagger2markup.pathsGroupedBy provided by swagger2Markup to specify how the paths should be grouped. However, Swagger2MarkupResultHandler do not provide API to support the configuration.
According to Swagger2Markup API,
The properties of Swagger2Markup are defined in the class
io.github.swagger2markup.Swagger2MarkupProperties. The properties are
considered in the following order:
Java System properties
Custom properties
Default properties (included in Swagger2Markup)
it is possible to configure it by using system properties. Therefore, you can set a system property of swagger2markup.pathsGroupedBy to TAGS in the test.
If you prefer to configure it with Java API, you may extend Swagger2MarkupResultHandler and override the handle method with the use of Swagger2MarkupConfigBuilder API.

Resources