Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make HTTP templates for observability work with subresources #39192

Merged
merged 2 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,17 @@ public class ObservabilityCustomizer implements HandlerChainCustomizer {
public List<ServerRestHandler> handlers(Phase phase, ResourceClass resourceClass,
ServerResourceMethod serverResourceMethod) {
if (phase.equals(Phase.AFTER_MATCH)) {
String basePath = resourceClass.getPath();
boolean isSubResource = basePath == null;
ObservabilityHandler observabilityHandler = new ObservabilityHandler();
observabilityHandler
.setTemplatePath(resourceClass.getPath() + serverResourceMethod.getPath());
if (isSubResource) {
observabilityHandler.setTemplatePath(serverResourceMethod.getPath());
observabilityHandler.setSubResource(true);
} else {
observabilityHandler.setTemplatePath(basePath + serverResourceMethod.getPath());
observabilityHandler.setSubResource(false);
}

return Collections.singletonList(observabilityHandler);
}
return Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class ObservabilityHandler implements ServerRestHandler {
// make mutable to allow for bytecode serialization
private String templatePath;

private boolean isSubResource;

public String getTemplatePath() {
return templatePath;
}
Expand All @@ -24,9 +26,26 @@ public void setTemplatePath(String templatePath) {
this.templatePath = MULTIPLE_SLASH_PATTERN.matcher(templatePath).replaceAll("/");
}

public boolean isSubResource() {
return isSubResource;
}

public void setSubResource(boolean subResource) {
isSubResource = subResource;
}

@Override
public void handle(ResteasyReactiveRequestContext requestContext) throws Exception {
setUrlPathTemplate(requestContext.unwrap(RoutingContext.class), templatePath);
RoutingContext routingContext = requestContext.unwrap(RoutingContext.class);
if (isSubResource) {
var previous = getUrlPathTemplate(routingContext);
if (previous == null) {
previous = "";
}
setUrlPathTemplate(routingContext, previous + templatePath);
} else {
setUrlPathTemplate(routingContext, templatePath);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.resteasy.reactive.server.runtime.observability;

import io.vertx.core.Context;
import io.vertx.core.http.impl.HttpServerRequestInternal;
import io.vertx.ext.web.RoutingContext;

Expand All @@ -9,7 +10,14 @@ private ObservabilityUtil() {
}

static void setUrlPathTemplate(RoutingContext routingContext, String templatePath) {
((HttpServerRequestInternal) (routingContext.request())).context()
.putLocal("UrlPathTemplate", templatePath);
getRequestContext(routingContext).putLocal("UrlPathTemplate", templatePath);
}

static String getUrlPathTemplate(RoutingContext routingContext) {
return getRequestContext(routingContext).getLocal("UrlPathTemplate");
}

private static Context getRequestContext(RoutingContext routingContext) {
return ((HttpServerRequestInternal) (routingContext.request())).context();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.quarkus.it.micrometer.prometheus;

import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;

@Path("/root")
public class RootResource {

@Path("{rootParam}/sub")
public SubResource subResource(@PathParam("rootParam") String value) {
return new SubResource(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.it.micrometer.prometheus;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;

public class SubResource {

private final String value;

public SubResource(String value) {
this.value = value;
}

@GET
@Path("/{subParam}")
public String get(@PathParam("subParam") String subParam) {
return value + ":" + subParam;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ void testSecuredEndpoint() {

@Test
@Order(11)
void testTemplatedPathOnSubResource() {
when().get("/root/r1/sub/s2").then().statusCode(200)
.body(containsString("r1:s2"));
}

@Test
@Order(20)
void testPrometheusScrapeEndpointTextPlain() {
RestAssured.given().header("Accept", TextFormat.CONTENT_TYPE_004)
.when().get("/q/metrics")
Expand Down Expand Up @@ -133,6 +140,9 @@ void testPrometheusScrapeEndpointTextPlain() {
.body(containsString(
"http_server_requests_seconds_count{dummy=\"value\",env=\"test\",env2=\"test\",foo=\"UNSET\",method=\"GET\",outcome=\"SUCCESS\",registry=\"prometheus\",status=\"200\",uri=\"/template/path/{value}\""))

.body(containsString(
"http_server_requests_seconds_count{dummy=\"value\",env=\"test\",env2=\"test\",foo=\"UNSET\",method=\"GET\",outcome=\"SUCCESS\",registry=\"prometheus\",status=\"200\",uri=\"/root/{rootParam}/sub/{subParam}\""))

// Verify Hibernate Metrics
.body(containsString(
"hibernate_sessions_open_total{entityManagerFactory=\"<default>\",env=\"test\",env2=\"test\",registry=\"prometheus\",} 2.0"))
Expand Down Expand Up @@ -195,7 +205,7 @@ void testPrometheusScrapeEndpointTextPlain() {
}

@Test
@Order(11)
@Order(20)
void testPrometheusScrapeEndpointOpenMetrics() {
RestAssured.given().header("Accept", TextFormat.CONTENT_TYPE_OPENMETRICS_100)
.when().get("/q/metrics")
Expand Down
Loading