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

Backport 16377 #16486

Merged
merged 3 commits into from
Apr 13, 2021
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
16 changes: 16 additions & 0 deletions extensions/micrometer/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-spi-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow-spi</artifactId>
</dependency>

<!-- test -->

Expand Down Expand Up @@ -77,6 +81,18 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow-deployment</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx-web-deployment</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.function.BooleanSupplier;

import javax.inject.Singleton;
import javax.servlet.DispatcherType;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
Expand Down Expand Up @@ -33,9 +34,10 @@ public class HttpBinderProcessor {
// Common MeterFilter (uri variation limiter)
static final String HTTP_METER_FILTER_CONFIGURATION = "io.quarkus.micrometer.runtime.binder.HttpMeterFilterProvider";

// avoid imports due to related deps not being there
// JAX-RS, Servlet Filters
static final String RESTEASY_CONTAINER_FILTER_CLASS_NAME = "io.quarkus.micrometer.runtime.binder.vertx.VertxMeterBinderRestEasyContainerFilter";
static final String QUARKUS_REST_CONTAINER_FILTER_CLASS_NAME = "io.quarkus.micrometer.runtime.binder.vertx.VertxMeterBinderQuarkusRestContainerFilter";
static final String RESTEASY_REACTIVE_CONTAINER_FILTER_CLASS_NAME = "io.quarkus.micrometer.runtime.binder.vertx.VertxMeterBinderRestEasyReactiveContainerFilter";
static final String UNDERTOW_SERVLET_FILTER_CLASS_NAME = "io.quarkus.micrometer.runtime.binder.vertx.VertxMeterBinderUndertowServletFilter";

// Rest client listener SPI
private static final String REST_CLIENT_LISTENER_CLASS_NAME = "org.eclipse.microprofile.rest.client.spi.RestClientListener";
Expand Down Expand Up @@ -100,15 +102,31 @@ FilterBuildItem addVertxMeterFilter() {
void enableHttpServerSupport(Capabilities capabilities,
BuildProducer<ResteasyJaxrsProviderBuildItem> resteasyJaxrsProviders,
BuildProducer<CustomContainerRequestFilterBuildItem> customContainerRequestFilter,
BuildProducer<io.quarkus.undertow.deployment.FilterBuildItem> servletFilters,
BuildProducer<AdditionalBeanBuildItem> additionalBeans) {

// Will have one or the other of these (exclusive)
if (capabilities.isPresent(Capability.RESTEASY)) {
resteasyJaxrsProviders.produce(new ResteasyJaxrsProviderBuildItem(RESTEASY_CONTAINER_FILTER_CLASS_NAME));
createAdditionalBean(additionalBeans, RESTEASY_CONTAINER_FILTER_CLASS_NAME);
} else if (capabilities.isPresent(Capability.RESTEASY_REACTIVE)) {
customContainerRequestFilter
.produce(new CustomContainerRequestFilterBuildItem(QUARKUS_REST_CONTAINER_FILTER_CLASS_NAME));
createAdditionalBean(additionalBeans, QUARKUS_REST_CONTAINER_FILTER_CLASS_NAME);
.produce(new CustomContainerRequestFilterBuildItem(RESTEASY_REACTIVE_CONTAINER_FILTER_CLASS_NAME));
createAdditionalBean(additionalBeans, RESTEASY_REACTIVE_CONTAINER_FILTER_CLASS_NAME);
}

// But this might be present as well (fallback. Rest URI processing preferred)
if (capabilities.isPresent(Capability.SERVLET)) {
servletFilters.produce(
io.quarkus.undertow.deployment.FilterBuildItem.builder("metricsFilter", UNDERTOW_SERVLET_FILTER_CLASS_NAME)
.setAsyncSupported(true)
.addFilterUrlMapping("*", DispatcherType.FORWARD)
.addFilterUrlMapping("*", DispatcherType.INCLUDE)
.addFilterUrlMapping("*", DispatcherType.REQUEST)
.addFilterUrlMapping("*", DispatcherType.ASYNC)
.addFilterUrlMapping("*", DispatcherType.ERROR)
.build());
createAdditionalBean(additionalBeans, UNDERTOW_SERVLET_FILTER_CLASS_NAME);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class HttpDevModeConfigTest {
"quarkus.micrometer.binder.vertx.enabled=true\n"), "application.properties"));

@Test
public void testHttpConfigInDevMode() throws Exception {
public void test() throws Exception {

when().get("/hello/one").then().statusCode(200);
when().get("/hello/two").then().statusCode(200);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package io.quarkus.micrometer.deployment.binder;

import static io.restassured.RestAssured.given;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.quarkus.micrometer.test.HelloResource;
import io.quarkus.micrometer.test.Util;
import io.quarkus.micrometer.test.VertxWebEndpoint;
import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class UriTagCorsTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withConfigurationResource("test-logging.properties")
.overrideConfigKey("quarkus.micrometer.binder-enabled-default", "false")
.overrideConfigKey("quarkus.micrometer.binder.http-server.enabled", "true")
.overrideConfigKey("quarkus.micrometer.binder.vertx.enabled", "true")
.overrideConfigKey("quarkus.http.cors", "true")
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(Util.class,
VertxWebEndpoint.class,
HelloResource.class));

static SimpleMeterRegistry registry = new SimpleMeterRegistry();

@BeforeAll
static void setRegistry() {
registry = new SimpleMeterRegistry();
Metrics.addRegistry(registry);
}

@AfterAll()
static void removeRegistry() {
Metrics.removeRegistry(registry);
}

@Test
public void testCORSPreflightRequest() {
String origin = "http://custom.origin.quarkus";
String methods = "GET,POST";
String headers = "X-Custom";
RestAssured.given()
.header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when().options("/hello/world").then()
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers)
.statusCode(200);

RestAssured.given()
.header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when().options("/vertx/echo/anything").then()
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers)
.statusCode(200);

RestAssured.given()
.header("Origin", origin)
.header("Access-Control-Request-Method", methods)
.header("Access-Control-Request-Headers", headers)
.when().options("/vertx/item/123").then()
.header("Access-Control-Allow-Origin", origin)
.header("Access-Control-Allow-Methods", methods)
.header("Access-Control-Allow-Headers", headers)
.statusCode(200);

RestAssured.given()
.when().options("/vertx/echo/anything").then()
.statusCode(200);

RestAssured.given()
.when().options("/hello/world").then()
.statusCode(200);

// CORS pre-flight
Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/cors-preflight").timers().size(),
Util.foundServerRequests(registry, "/cors-preflight should be used for preflight requests"));
Timer t = registry.find("http.server.requests").tag("uri", "/cors-preflight").timer();
Assertions.assertEquals(3, t.count(), "/cors-preflight checked twice");

// Normal OPTIONS requests
Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/vertx/echo/{msg}").timers().size(),
Util.foundServerRequests(registry, "/vertx/echo/{msg} for options request"));
Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/hello/{message}").timers().size(),
Util.foundServerRequests(registry, "/hello/{message} for options request"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package io.quarkus.micrometer.deployment.binder;

import static io.restassured.RestAssured.when;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.quarkus.micrometer.test.HelloResource;
import io.quarkus.micrometer.test.PingPongResource;
import io.quarkus.micrometer.test.ServletEndpoint;
import io.quarkus.micrometer.test.Util;
import io.quarkus.micrometer.test.VertxWebEndpoint;
import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class UriTagTest {
@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withConfigurationResource("test-logging.properties")
.overrideConfigKey("quarkus.micrometer.binder-enabled-default", "false")
.overrideConfigKey("quarkus.micrometer.binder.http-client.enabled", "true")
.overrideConfigKey("quarkus.micrometer.binder.http-server.enabled", "true")
.overrideConfigKey("quarkus.micrometer.binder.http-server.match-patterns", "/one=/two")
.overrideConfigKey("quarkus.micrometer.binder.http-server.ignore-patterns", "/two")
.overrideConfigKey("quarkus.micrometer.binder.vertx.enabled", "true")
.overrideConfigKey("pingpong/mp-rest/url", "${test.url}")
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(Util.class,
PingPongResource.class,
PingPongResource.PingPongRestClient.class,
ServletEndpoint.class,
VertxWebEndpoint.class,
HelloResource.class));

static SimpleMeterRegistry registry = new SimpleMeterRegistry();

@BeforeAll
static void setRegistry() {
registry = new SimpleMeterRegistry();
Metrics.addRegistry(registry);
}

@AfterAll()
static void removeRegistry() {
Metrics.removeRegistry(registry);
}

@Test
public void testGetRequests() throws Exception {
RestAssured.basePath = "/";

// If you invoke requests, http server and client meters should be registered

when().get("/one").then().statusCode(200);
when().get("/two").then().statusCode(200);
when().get("/ping/one").then().statusCode(200);
when().get("/ping/two").then().statusCode(200);
when().get("/ping/three").then().statusCode(200);
when().get("/vertx/item/123").then().statusCode(200);
when().get("/vertx/item/1/123").then().statusCode(200);
when().get("/servlet/12345").then().statusCode(200);

System.out.println("Server paths\n" + Util.listMeters(registry, "http.server.requests"));
System.out.println("Client paths\n" + Util.listMeters(registry, "http.client.requests"));

// /one should map to /two, which is ignored. Neither should exist w/ timers
Assertions.assertEquals(0, registry.find("http.server.requests").tag("uri", "/one").timers().size(),
Util.foundServerRequests(registry, "/one is mapped to /two, which should be ignored."));
Assertions.assertEquals(0, registry.find("http.server.requests").tag("uri", "/two").timers().size(),
Util.foundServerRequests(registry, "/two should be ignored."));

// URIs for server: /ping/{message}, /pong/{message}, /vertx/item/{id}, /vertx/item/{id}/{sub}, /servlet/
Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/ping/{message}").timers().size(),
Util.foundServerRequests(registry, "/ping/{message} should be returned by JAX-RS."));
Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/pong/{message}").timers().size(),
Util.foundServerRequests(registry, "/pong/{message} should be returned by JAX-RS."));
Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/vertx/item/{id}").timers().size(),
Util.foundServerRequests(registry,
"Vert.x Web template path (/vertx/item/:id) should be detected/translated to /vertx/item/{id}."));
Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/vertx/item/{id}/{sub}").timers().size(),
Util.foundServerRequests(registry,
"Vert.x Web template path (/vertx/item/:id/:sub) should be detected/translated to /vertx/item/{id}/{sub}."));
Assertions.assertEquals(1, registry.find("http.server.requests").tag("uri", "/servlet").timers().size(),
Util.foundServerRequests(registry, "Servlet path (/servlet) should be used for servlet"));

// TODO: #15231
// URIs For client: /pong/{message}
// Assertions.assertEquals(1, registry.find("http.client.requests").tag("uri", "/pong/{message}").timers().size(),
// Util.foundClientRequests(registry, "/pong/{message} should be returned by Rest client."));

when().get("/hello/one").then().statusCode(200);
when().get("/hello/two").then().statusCode(200);
when().head("/hello/three").then().statusCode(200);
when().head("/hello/four").then().statusCode(200);
when().get("/vertx/echo/thing1").then().statusCode(200);
when().get("/vertx/echo/thing2").then().statusCode(200);
when().head("/vertx/echo/thing3").then().statusCode(200);
when().head("/vertx/echo/thing4").then().statusCode(200);

// GET and HEAD are two different methods, so double these up
Assertions.assertEquals(2, registry.find("http.server.requests").tag("uri", "/hello/{message}").timers().size(),
Util.foundServerRequests(registry, "/hello/{message} should have two timers (GET and HEAD)."));
Assertions.assertEquals(2, registry.find("http.server.requests").tag("uri", "/vertx/echo/{msg}").timers().size(),
Util.foundServerRequests(registry, "/vertx/echo/{msg} should have two timers (GET and HEAD)."));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
import static io.restassured.RestAssured.when;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
Expand All @@ -14,57 +11,48 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.micrometer.core.instrument.MeterRegistry;
import io.quarkus.micrometer.runtime.config.runtime.HttpClientConfig;
import io.quarkus.micrometer.runtime.config.runtime.HttpServerConfig;
import io.quarkus.micrometer.test.HelloResource;
import io.quarkus.micrometer.test.PingPongResource;
import io.quarkus.test.QuarkusUnitTest;

public class HttpWithLimitedUriTest {
public class UriWithMaxTagMeterFilterTest {
@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withConfigurationResource("test-logging.properties")
.overrideConfigKey("quarkus.micrometer.binder-enabled-default", "false")
.overrideConfigKey("quarkus.micrometer.binder.http-client.enabled", "true")
.overrideConfigKey("quarkus.micrometer.binder.http-client.max-uri-tags", "1")
.overrideConfigKey("quarkus.micrometer.binder.http-server.enabled", "true")
.overrideConfigKey("quarkus.micrometer.binder.http-server.max-uri-tags", "1")
.overrideConfigKey("quarkus.micrometer.export.prometheus.enabled", "true")
.overrideConfigKey("quarkus.micrometer.binder.vertx.enabled", "true")
.overrideConfigKey("pingpong/mp-rest/url", "${test.url}")
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClass(EchoResource.class));
.addClasses(HelloResource.class, PingPongResource.class, PingPongResource.PingPongRestClient.class));

@Inject
HttpServerConfig httpServerConfig;
@Inject
HttpClientConfig httpClientConfig;

@Inject
MeterRegistry registry;

@Test
public void testMetricFactoryCreatedMetrics() throws Exception {
public void test() throws Exception {
Assertions.assertEquals(1, httpServerConfig.maxUriTags);
Assertions.assertEquals(1, httpClientConfig.maxUriTags);

// Now let's poke the bear

// Rest requests are nicely parameterized (should remain @ 1)
when().get("/echo/ping").then().statusCode(200);
when().get("/echo/pong").then().statusCode(200);
when().get("/echo/other").then().statusCode(200);
// Server limit is constrained to 1
when().get("/ping/one").then().statusCode(200);
when().get("/ping/two").then().statusCode(200);
when().get("/ping/three").then().statusCode(200);
when().get("/one").then().statusCode(200);
Assertions.assertEquals(1, registry.find("http.server.requests").timers().size());

// we set a limit of 1. If we now request the other URL.. it should not appear in metrics
when().get("/other").then().statusCode(200);
Assertions.assertEquals(1, registry.find("http.server.requests").timers().size());
// Client limit is constrained to 1
Assertions.assertEquals(1, registry.find("http.client.requests").timers().size());
}

@Path("/")
public static class EchoResource {
@GET
@Path("/echo/{message}")
public String echo(@PathParam("message") String message) {
return message;
}

@GET
@Path("/other")
public String other() {
return "boo";
}
}

}
Loading