[
https://issues.apache.org/jira/browse/CXF-9211?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
der-brecher updated CXF-9211:
-----------------------------
Description:
This is a clone of the already closed CXF-8424. Unfortunatly, the fixes do not
address proxy-API based clients. I can confirm this issue holds for v3.5.11 and
v.4.2.0.
The JAX-RS micrometer metrics generates one unique metric per combination of
path parameteres in the URL. For instance if you have the following path
annotation on an API:
{code:java}
@Path("/item/{id}" {code}
Requesting _/item/1234_ will result in the following metric:
{code:java}
[...],metric=timers,name="cxfClientRequests:exception=None,method=POST,operation=item,outcome=SUCCESS,service=MyService,status=200,uri=http://localhost:8099/item/1234"{code}
...but it should be...
{code:java}
[...],metric=timers,name="cxfClientRequests:exception=None,method=POST,operation=item,outcome=SUCCESS,service=MyService,status=200,uri=http://localhost:8099/item/{id}"
{code}
I managed to workaround this issue by implementing an Interceptor right before
org.apache.cxf.metrics.interceptors.MetricsMessageInPostInvokeInterceptor
poking the org.apache.cxf.jaxrs.model.URITemplate.URI_TEMPLATE attribute into
the request message.
Please provide this attribute out of the box.
As a reference this is my workaround code:
{code:java}
public JaxRsTemplateUriFixClientInInterceptor() {
super(Phase.POST_INVOKE);
addBefore(MetricsMessageInPostInvokeInterceptor.class.getName());
}
@Override
public void handleMessage(final Message pMessage) throws Fault {
if (!isRequestor(pMessage) ||
MessageUtils.isOutbound(pMessage)) {
return; // only for client side responses
}
final Message request = pMessage.getExchange().getOutMessage();
request.computeIfAbsent(URITemplate.URI_TEMPLATE, k -> {
final String basePath =
Optional.ofNullable(request.get(Message.BASE_PATH)).filter(String.class::isInstance).map(String.class::cast).orElse(null);
final Method method =
Optional.ofNullable(pMessage.getExchange().get(Method.class.getName())).filter(Method.class::isInstance).map(Method.class::cast).orElse(null);
final Path path =
AnnotationUtils.getMethodAnnotation(method, Path.class);
if (basePath == null || path == null) {
return null;
}
return basePath +
URITemplate.createTemplate(path).getValue();
});
}
{code}
was:
The JAX-RS micrometer metrics implemented in the PRs listed below generates one
unique metric per combination of path parameteres in the URL. For instance if
you have the following path annotation on an API:
{code:java}
@Path("/user/{userId}" {code}
A request to the URL _/user/1234_ will result in the following metric:
{code:java}
cxf_server_requests_seconds_count{exception="None",method="GET",operation="getUser",outcome="SUCCESS",status="200",uri="/user/1234",}
1.0 {code}
Since the uri-tag in the metric uses the actual path value this could lead to a
huge number of metrics since it will create one metric per user. It will also
be more difficult to aggregate the metrics for one operation in tools like
Prometheus/Grafana.
A suggestion is to instead generate the metric with the uri-tag as a templated
url. I think this is how the metrics generated by Spring MVC is constructed.
This would result in the following metric instead:
{code:java}
cxf_server_requests_seconds_count{exception="None",method="GET",operation="getUser",outcome="SUCCESS",status="200",uri="/user/{userId}",}
1.0 {code}
Not sure if this is possible and what the best solution is, but it might be
possible to use the UriInfo class
([https://javaee.github.io/javaee-spec/javadocs/javax/ws/rs/core/UriInfo.html)]
to get the URI without the values, or use that class to replace the actual
values with a placeholder/variable text.
Relevant PRs:
[https://github.com/apache/cxf/pull/716]
[https://github.com/apache/cxf/pull/642]
> [JAX-RS proxy clients] Use template URL instead of actual path values for
> JAX-RS micrometer metrics
> ---------------------------------------------------------------------------------------------------
>
> Key: CXF-9211
> URL: https://issues.apache.org/jira/browse/CXF-9211
> Project: CXF
> Issue Type: Improvement
> Components: JAX-RS
> Affects Versions: 4.2.0, 3.5.11
> Reporter: der-brecher
> Assignee: Andriy Redko
> Priority: Minor
>
> This is a clone of the already closed CXF-8424. Unfortunatly, the fixes do
> not address proxy-API based clients. I can confirm this issue holds for
> v3.5.11 and v.4.2.0.
> The JAX-RS micrometer metrics generates one unique metric per combination of
> path parameteres in the URL. For instance if you have the following path
> annotation on an API:
> {code:java}
> @Path("/item/{id}" {code}
> Requesting _/item/1234_ will result in the following metric:
> {code:java}
> [...],metric=timers,name="cxfClientRequests:exception=None,method=POST,operation=item,outcome=SUCCESS,service=MyService,status=200,uri=http://localhost:8099/item/1234"{code}
> ...but it should be...
>
> {code:java}
> [...],metric=timers,name="cxfClientRequests:exception=None,method=POST,operation=item,outcome=SUCCESS,service=MyService,status=200,uri=http://localhost:8099/item/{id}"
> {code}
>
> I managed to workaround this issue by implementing an Interceptor right
> before
> org.apache.cxf.metrics.interceptors.MetricsMessageInPostInvokeInterceptor
> poking the org.apache.cxf.jaxrs.model.URITemplate.URI_TEMPLATE attribute into
> the request message.
> Please provide this attribute out of the box.
> As a reference this is my workaround code:
> {code:java}
> public JaxRsTemplateUriFixClientInInterceptor() {
> super(Phase.POST_INVOKE);
>
> addBefore(MetricsMessageInPostInvokeInterceptor.class.getName());
> }
>
> @Override
> public void handleMessage(final Message pMessage) throws Fault {
> if (!isRequestor(pMessage) ||
> MessageUtils.isOutbound(pMessage)) {
> return; // only for client side responses
> }
> final Message request = pMessage.getExchange().getOutMessage();
>
> request.computeIfAbsent(URITemplate.URI_TEMPLATE, k -> {
> final String basePath =
> Optional.ofNullable(request.get(Message.BASE_PATH)).filter(String.class::isInstance).map(String.class::cast).orElse(null);
> final Method method =
> Optional.ofNullable(pMessage.getExchange().get(Method.class.getName())).filter(Method.class::isInstance).map(Method.class::cast).orElse(null);
> final Path path =
> AnnotationUtils.getMethodAnnotation(method, Path.class);
> if (basePath == null || path == null) {
> return null;
> }
> return basePath +
> URITemplate.createTemplate(path).getValue();
> });
> }
> {code}
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)