This is an automated email from the ASF dual-hosted git repository. ycai pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git
The following commit(s) were added to refs/heads/trunk by this push: new 7a5e710 CASSANDRASC-34: Allow for LoggerHandler to be injected 7a5e710 is described below commit 7a5e710a2173e492907edc4094e052157a562103 Author: Francisco Guerrero <francisco.guerr...@apple.com> AuthorDate: Fri Mar 11 15:43:24 2022 -0800 CASSANDRASC-34: Allow for LoggerHandler to be injected Currently, `vertxRouter` adds an instance of `LoggerHandler` to the top level route. This is prescriptive and it doesn't allow for a different implementation of the LoggerHandler to be injected. In this commit, `LoggerHandler` is created in the `MainModule` as a singleton and then injected in the `vertxRouter` method. This allows for a new implementation of the `LoggerHandler` to be provided. --- CHANGES.txt | 1 + gradle.properties | 2 +- .../org/apache/cassandra/sidecar/MainModule.java | 11 +- .../sidecar/LoggerHandlerInjectionTest.java | 147 +++++++++++++++++++++ 4 files changed, 158 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index c72ce7d..27ce525 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,6 @@ 1.0.0 ----- + * Allow injecting a LoggerHandler to vertxRouter (CASSANDRASC-34) * Optionally support multiple cassandra instances in Sidecar (CASSANDRASC-33) * Call the start method of CassandraAdaptorDelegate to start periodic health check (CASSANDRASC-32) * Avoid having sidecar's health response code depend on Cassandra's health information (CASSANDRASC-29) diff --git a/gradle.properties b/gradle.properties index c9d988b..f004357 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ version=1.0-SNAPSHOT junitVersion=5.4.2 kubernetesClientVersion=9.0.0 -cassandra40Version=4.0.1 +cassandra40Version=4.0.3 vertxVersion=4.2.1 diff --git a/src/main/java/org/apache/cassandra/sidecar/MainModule.java b/src/main/java/org/apache/cassandra/sidecar/MainModule.java index 32c3548..a7eb33d 100644 --- a/src/main/java/org/apache/cassandra/sidecar/MainModule.java +++ b/src/main/java/org/apache/cassandra/sidecar/MainModule.java @@ -129,10 +129,10 @@ public class MainModule extends AbstractModule @Provides @Singleton - public Router vertxRouter(Vertx vertx) + public Router vertxRouter(Vertx vertx, LoggerHandler loggerHandler) { Router router = Router.router(vertx); - router.route().handler(LoggerHandler.create()); + router.route().handler(loggerHandler); // Static web assets for Swagger StaticHandler swaggerStatic = StaticHandler.create("META-INF/resources/webjars/swagger-ui"); @@ -254,4 +254,11 @@ public class MainModule extends AbstractModule { return SidecarRateLimiter.create(config.getRateLimitStreamRequestsPerSecond()); } + + @Provides + @Singleton + public LoggerHandler loggerHandler() + { + return LoggerHandler.create(); + } } diff --git a/src/test/java/org/apache/cassandra/sidecar/LoggerHandlerInjectionTest.java b/src/test/java/org/apache/cassandra/sidecar/LoggerHandlerInjectionTest.java new file mode 100644 index 0000000..d658ddb --- /dev/null +++ b/src/test/java/org/apache/cassandra/sidecar/LoggerHandlerInjectionTest.java @@ -0,0 +1,147 @@ +package org.apache.cassandra.sidecar; + +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.util.Modules; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.client.HttpResponse; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.codec.BodyCodec; +import io.vertx.ext.web.handler.HttpException; +import io.vertx.ext.web.handler.LoggerFormatter; +import io.vertx.ext.web.handler.LoggerHandler; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; + +import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; +import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@DisplayName("LoggerHandler Injection Test") +@ExtendWith(VertxExtension.class) +public class LoggerHandlerInjectionTest +{ + private Vertx vertx; + private Configuration config; + private final Logger logger = mock(Logger.class); + + @BeforeEach + void setUp() throws InterruptedException + { + FakeLoggerHandler loggerHandler = new FakeLoggerHandler(logger); + Injector injector = Guice.createInjector(Modules.override(Modules.override(new MainModule()).with(new TestModule())) + .with(binder -> binder.bind(LoggerHandler.class).toInstance(loggerHandler))); + vertx = injector.getInstance(Vertx.class); + config = injector.getInstance(Configuration.class); + Router router = injector.getInstance(Router.class); + + router.get("/500-route").handler(p -> { + throw new RuntimeException("Fails with 500"); + }); + + router.get("/404-route").handler(p -> { + throw new HttpException(NOT_FOUND.code(), "Sorry, it's not here"); + }); + + router.get("/204-route").handler(p -> { + throw new HttpException(NO_CONTENT.code(), "Sorry, no content"); + }); + + VertxTestContext context = new VertxTestContext(); + HttpServer server = injector.getInstance(HttpServer.class); + server.listen(config.getPort(), context.succeedingThenComplete()); + + context.awaitCompletion(5, TimeUnit.SECONDS); + } + + @DisplayName("Should log at error level when the request fails with a 500 code") + @Test + public void testInjectedLoggerHandlerLogsAtErrorLevel(VertxTestContext testContext) + { + helper("/500-route", testContext, 500, "Internal Server Error"); + } + + @DisplayName("Should log at warn level when the request fails with a 404 error") + @Test + public void testInjectedLoggerHandlerLogsAtWarnLevel(VertxTestContext testContext) + { + helper("/404-route", testContext, 404, "Not Found"); + } + + @DisplayName("Should log at info level when the request returns with a 500 error") + @Test + public void testInjectedLoggerHandlerLogsAtInfoLevel(VertxTestContext testContext) + { + helper("/204-route", testContext, 204, null); + } + + private void helper(String requestURI, VertxTestContext testContext, int expectedStatusCode, String expectedBody) + { + WebClient client = WebClient.create(vertx); + Handler<HttpResponse<String>> responseVerifier = response -> testContext.verify( + () -> { + assertThat(response.statusCode()).isEqualTo(expectedStatusCode); + if (expectedBody == null) + { + assertThat(response.body()).isNull(); + } + else + { + assertThat(response.body()).isEqualTo(expectedBody); + } + testContext.completeNow(); + verify(logger, times(1)).info("{}", expectedStatusCode); + }); + client.get(config.getPort(), "localhost", requestURI) + .as(BodyCodec.string()) + .ssl(false) + .send(testContext.succeeding(responseVerifier)); + } + + private static class FakeLoggerHandler implements LoggerHandler + { + private final Logger logger; + + FakeLoggerHandler(Logger logger) + { + this.logger = logger; + } + + @Override + public LoggerHandler customFormatter(Function<HttpServerRequest, String> formatter) + { + return this; + } + + @Override + public LoggerHandler customFormatter(LoggerFormatter formatter) + { + return this; + } + + @Override + public void handle(RoutingContext context) + { + HttpServerRequest request = context.request(); + context.addBodyEndHandler(v -> logger.info("{}", request.response().getStatusCode())); + context.next(); + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org