From 623cb4a2e07c6d05a0cf0ef5022e288f19a9ad21 Mon Sep 17 00:00:00 2001 From: Graeme Rocher Date: Tue, 28 May 2024 12:48:12 +0200 Subject: [PATCH 1/4] jetty access log support --- .../servlet/jetty/JettyConfiguration.java | 72 +++++++++++++++++++ .../micronaut/servlet/jetty/JettyFactory.java | 10 +++ .../servlet/jetty/JettyRequestLogSpec.groovy | 37 ++++++++++ 3 files changed, 119 insertions(+) create mode 100644 http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyRequestLogSpec.groovy diff --git a/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyConfiguration.java b/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyConfiguration.java index 1f324ad20..939b279ff 100644 --- a/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyConfiguration.java +++ b/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyConfiguration.java @@ -18,12 +18,19 @@ import io.micronaut.context.annotation.ConfigurationBuilder; import io.micronaut.context.annotation.ConfigurationProperties; import io.micronaut.context.annotation.Replaces; +import io.micronaut.context.annotation.Requires; +import io.micronaut.core.annotation.NonNull; import io.micronaut.core.convert.format.MapFormat; import io.micronaut.core.naming.conventions.StringConvention; +import io.micronaut.core.util.StringUtils; +import io.micronaut.core.util.Toggleable; import io.micronaut.http.server.HttpServerConfiguration; +import jakarta.inject.Inject; +import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.HttpConfiguration; import io.micronaut.core.annotation.Nullable; +import org.eclipse.jetty.server.RequestLogWriter; import org.eclipse.jetty.server.SecureRequestCustomizer; import java.util.Collections; @@ -42,6 +49,7 @@ public class JettyConfiguration extends HttpServerConfiguration { @ConfigurationBuilder protected HttpConfiguration httpConfiguration = new HttpConfiguration(); + private final JettyRequestLog requestLog; private final MultipartConfiguration multipartConfiguration; private Map initParameters; @@ -51,7 +59,17 @@ public class JettyConfiguration extends HttpServerConfiguration { * @param multipartConfiguration The multipart configuration. */ public JettyConfiguration(@Nullable MultipartConfiguration multipartConfiguration) { + this(null, null); + } + + /** + * Default constructor. + * @param multipartConfiguration The multipart configuration. + */ + @Inject + public JettyConfiguration(@Nullable MultipartConfiguration multipartConfiguration, @Nullable JettyRequestLog requestLog) { this.multipartConfiguration = multipartConfiguration; + this.requestLog = requestLog; } /** @@ -68,6 +86,13 @@ public Optional getMultipartConfiguration() { return Optional.ofNullable(multipartConfiguration); } + /** + * @return The request log configuration. + */ + public Optional getRequestLog() { + return Optional.ofNullable(requestLog); + } + /** * @return The servlet init parameters */ @@ -98,4 +123,51 @@ public void setInitParameters( public static class JettySslConfiguration extends SecureRequestCustomizer { } + /** + * Jetty access log configuration. + * + * @since 4.8.0 + */ + @ConfigurationProperties(JettyRequestLog.ACCESS_LOG) + @Requires(property = JettyRequestLog.ENABLED, value = StringUtils.TRUE) + public static class JettyRequestLog implements Toggleable { + public static final String ACCESS_LOG = "access-log"; + public static final String ENABLED = JettyConfiguration.PREFIX + ".jetty." + ACCESS_LOG + ".enabled"; + @ConfigurationBuilder(prefixes = "set", excludes = "eventListeners") + RequestLogWriter requestLogWriter = new RequestLogWriter(); + + private boolean enabled = true; + private String pattern = CustomRequestLog.EXTENDED_NCSA_FORMAT; + + @Override + public boolean isEnabled() { + return enabled; + } + + /** + * Whether access log is enabled. + * @param enabled True if it is enabled. + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + /** + * The pattern to use for the access log. Defaults to {@code EXTENDED_NCSA_FORMAT}. + * + * @return The pattern. + */ + public @NonNull String getPattern() { + return pattern; + } + + /** + * Sets the pattern to use for the access log. Defaults to CustomRequestLog.EXTENDED_NCSA_FORMAT. + * + * @param pattern The pattern + */ + public void setPattern(String pattern) { + this.pattern = pattern; + } + } } diff --git a/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyFactory.java b/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyFactory.java index c110c3474..6211ab827 100644 --- a/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyFactory.java +++ b/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyFactory.java @@ -49,6 +49,7 @@ import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory; import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; @@ -147,6 +148,15 @@ protected Server jettyServer( Server server = newServer(applicationContext, configuration); + jettyConfiguration.getRequestLog().ifPresent(requestLog -> { + if (requestLog.isEnabled()) { + server.setRequestLog(new CustomRequestLog( + requestLog.requestLogWriter, + requestLog.getPattern() + )); + } + }); + final ServletContextHandler contextHandler = newJettyContext(server, contextPath); configureServletInitializer(server, contextHandler, servletContainerInitializers); diff --git a/http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyRequestLogSpec.groovy b/http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyRequestLogSpec.groovy new file mode 100644 index 000000000..ebbd08a67 --- /dev/null +++ b/http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyRequestLogSpec.groovy @@ -0,0 +1,37 @@ +package io.micronaut.servlet.jetty + +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import io.micronaut.test.support.TestPropertyProvider +import jakarta.inject.Inject +import org.eclipse.jetty.server.CustomRequestLog +import org.eclipse.jetty.server.Server +import spock.lang.Specification + +import java.nio.file.Files + +@MicronautTest +class JettyRequestLogSpec extends Specification implements TestPropertyProvider{ + @Inject + JettyConfiguration.JettyRequestLog requestLog + + @Inject Server server + + void "test configuration"() { + expect: + requestLog.enabled + requestLog.requestLogWriter.retainDays == 10 + requestLog.requestLogWriter.fileName != null + requestLog.pattern == CustomRequestLog.NCSA_FORMAT + server.requestLog != null + } + + @Override + Map getProperties() { + return [ + "micronaut.server.jetty.access-log.enabled": true, + "micronaut.server.jetty.access-log.filename": Files.createTempFile('log', 'test').toAbsolutePath().toString(), + "micronaut.server.jetty.access-log.retain-days": 10, + "micronaut.server.jetty.access-log.pattern": CustomRequestLog.NCSA_FORMAT + ] + } +} From dc831c57a6859f2073a0c69d40119d616e120468 Mon Sep 17 00:00:00 2001 From: Graeme Rocher Date: Tue, 28 May 2024 17:13:24 +0200 Subject: [PATCH 2/4] Support access log configuration in servlet servers --- ...gSpec.groovy => JettyAccessLogSpec.groovy} | 2 +- .../servlet/tomcat/TomcatConfiguration.java | 42 ++++++ .../servlet/tomcat/TomcatFactory.java | 14 ++ .../servlet/tomcat/TomcatAccessLogSpec.groovy | 34 +++++ .../undertow/UndertowConfiguration.java | 124 ++++++++++++++++-- .../servlet/undertow/UndertowFactory.java | 30 ++++- .../undertow/UndertowAccessLogSpec.groovy | 59 +++++++++ 7 files changed, 284 insertions(+), 21 deletions(-) rename http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/{JettyRequestLogSpec.groovy => JettyAccessLogSpec.groovy} (93%) create mode 100644 http-server-tomcat/src/test/groovy/io/micronaut/servlet/tomcat/TomcatAccessLogSpec.groovy create mode 100644 http-server-undertow/src/test/groovy/io/micronaut/servlet/undertow/UndertowAccessLogSpec.groovy diff --git a/http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyRequestLogSpec.groovy b/http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyAccessLogSpec.groovy similarity index 93% rename from http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyRequestLogSpec.groovy rename to http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyAccessLogSpec.groovy index ebbd08a67..ab9686d3e 100644 --- a/http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyRequestLogSpec.groovy +++ b/http-server-jetty/src/test/groovy/io/micronaut/servlet/jetty/JettyAccessLogSpec.groovy @@ -10,7 +10,7 @@ import spock.lang.Specification import java.nio.file.Files @MicronautTest -class JettyRequestLogSpec extends Specification implements TestPropertyProvider{ +class JettyAccessLogSpec extends Specification implements TestPropertyProvider { @Inject JettyConfiguration.JettyRequestLog requestLog diff --git a/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatConfiguration.java b/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatConfiguration.java index f0484bf98..fa646c4af 100644 --- a/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatConfiguration.java +++ b/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatConfiguration.java @@ -15,6 +15,10 @@ */ package io.micronaut.servlet.tomcat; +import io.micronaut.context.annotation.Requires; +import io.micronaut.core.util.StringUtils; +import io.micronaut.core.util.Toggleable; +import jakarta.inject.Inject; import java.util.Optional; import io.micronaut.context.annotation.ConfigurationBuilder; @@ -25,6 +29,7 @@ import io.micronaut.core.annotation.TypeHint; import io.micronaut.http.server.HttpServerConfiguration; import org.apache.catalina.connector.Connector; +import org.apache.catalina.valves.ExtendedAccessLogValve; import org.apache.coyote.ajp.AjpNio2Protocol; import org.apache.coyote.ajp.AjpNioProtocol; import org.apache.coyote.http11.Http11Nio2Protocol; @@ -54,6 +59,8 @@ public class TomcatConfiguration extends HttpServerConfiguration { private final MultipartConfiguration multipartConfiguration; private String protocol; + private AccessLogConfiguration accessLogConfiguration; + /** * Default constructor. * @param multipartConfiguration The multipart config @@ -97,4 +104,39 @@ public Optional getMultipartConfiguration() { return Optional.ofNullable(multipartConfiguration); } + /** + * @return The access log configuration. + * @since 4.8.0 + */ + public Optional getAccessLogConfiguration() { + return Optional.ofNullable(accessLogConfiguration); + } + + /** + * Sets the access log configuration. + * @param accessLogConfiguration The access log configuration. + * @since 4.8.0 + */ + @Inject + public void setAccessLogConfiguration(@Nullable AccessLogConfiguration accessLogConfiguration) { + this.accessLogConfiguration = accessLogConfiguration; + } + + /** + * The access log configuration. + * @since 4.8.0 + */ + @ConfigurationProperties(value = AccessLogConfiguration.PREFIX, excludes = {"next", "container"}) + @Requires(property = AccessLogConfiguration.ENABLED, value = StringUtils.TRUE) + public static class AccessLogConfiguration extends ExtendedAccessLogValve implements Toggleable { + + public static final String PREFIX = "access-log"; + + public static final String ENABLED = TomcatConfiguration.PREFIX + ".tomcat." + PREFIX + ".enabled"; + + @Override + public boolean isEnabled() { + return super.enabled; + } + } } diff --git a/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatFactory.java b/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatFactory.java index 7b4a2d479..89c77f31e 100644 --- a/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatFactory.java +++ b/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatFactory.java @@ -43,8 +43,10 @@ import io.micronaut.servlet.engine.server.ServletStaticResourceConfiguration; import jakarta.inject.Singleton; import java.util.Set; +import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.connector.Connector; +import org.apache.catalina.core.ContainerBase; import org.apache.catalina.startup.Tomcat; import org.apache.coyote.ProtocolHandler; import org.apache.coyote.http2.Http2Protocol; @@ -127,6 +129,18 @@ protected Tomcat tomcatServer( configureServletInitializer(context, servletInitializers); configureConnectors(tomcat, connector, httpsConnector); + TomcatConfiguration serverConfiguration = getServerConfiguration(); + serverConfiguration.getAccessLogConfiguration().ifPresent(accessValve -> { + if (accessValve.isEnabled()) { + Container[] children = tomcat.getHost().findChildren(); + for (Container child : children) { + if (child instanceof ContainerBase containerBase) { + containerBase.addValve(accessValve); + } + } + } + }); + return tomcat; } diff --git a/http-server-tomcat/src/test/groovy/io/micronaut/servlet/tomcat/TomcatAccessLogSpec.groovy b/http-server-tomcat/src/test/groovy/io/micronaut/servlet/tomcat/TomcatAccessLogSpec.groovy new file mode 100644 index 000000000..427abbaeb --- /dev/null +++ b/http-server-tomcat/src/test/groovy/io/micronaut/servlet/tomcat/TomcatAccessLogSpec.groovy @@ -0,0 +1,34 @@ +package io.micronaut.servlet.tomcat + +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import io.micronaut.test.support.TestPropertyProvider +import jakarta.inject.Inject +import org.apache.catalina.Valve +import org.apache.catalina.startup.Tomcat +import org.apache.catalina.valves.Constants +import spock.lang.Specification + +import java.nio.file.Files + +@MicronautTest +class TomcatAccessLogSpec extends Specification implements TestPropertyProvider { + @Inject TomcatConfiguration.AccessLogConfiguration accessLogConfiguration + @Inject Tomcat tomcat + + void "test access log"() { + expect: + accessLogConfiguration.enabled + accessLogConfiguration.pattern == Constants.AccessLog.COMBINED_PATTERN + def valves = tomcat.host.findChildren().first().pipeline.valves + valves + valves.first() instanceof TomcatConfiguration.AccessLogConfiguration + } + + @Override + Map getProperties() { + return [ + "micronaut.server.tomcat.access-log.enabled": true, + "micronaut.server.tomcat.access-log.pattern": Constants.AccessLog.COMBINED_PATTERN + ] + } +} diff --git a/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowConfiguration.java b/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowConfiguration.java index 3b0b49372..77f0f58b0 100644 --- a/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowConfiguration.java +++ b/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowConfiguration.java @@ -18,17 +18,24 @@ import io.micronaut.context.annotation.ConfigurationBuilder; import io.micronaut.context.annotation.ConfigurationProperties; import io.micronaut.context.annotation.Replaces; +import io.micronaut.context.annotation.Requires; +import io.micronaut.core.annotation.Nullable; import io.micronaut.core.annotation.TypeHint; import io.micronaut.core.convert.format.MapFormat; import io.micronaut.core.naming.conventions.StringConvention; +import io.micronaut.core.util.StringUtils; +import io.micronaut.core.util.Toggleable; import io.micronaut.http.server.HttpServerConfiguration; +import io.micronaut.scheduling.TaskExecutors; import io.undertow.Undertow; import io.undertow.UndertowOptions; - -import io.micronaut.core.annotation.Nullable; +import io.undertow.server.handlers.accesslog.DefaultAccessLogReceiver; +import jakarta.inject.Inject; +import jakarta.inject.Named; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.concurrent.ExecutorService; /** * Configuration for the Undertow server. @@ -38,8 +45,8 @@ */ @ConfigurationProperties("undertow") @TypeHint( - value = {UndertowOptions.class, org.xnio.Option.class}, - accessType = TypeHint.AccessType.ALL_DECLARED_FIELDS + value = {UndertowOptions.class, org.xnio.Option.class}, + accessType = TypeHint.AccessType.ALL_DECLARED_FIELDS ) @Replaces(HttpServerConfiguration.class) public class UndertowConfiguration extends HttpServerConfiguration { @@ -48,18 +55,38 @@ public class UndertowConfiguration extends HttpServerConfiguration { protected Undertow.Builder undertowBuilder = Undertow.builder(); private final MultipartConfiguration multipartConfiguration; + private AccessLogConfiguration accessLogConfiguration; private Map workerOptions = new HashMap<>(5); private Map socketOptions = new HashMap<>(5); private Map serverOptions = new HashMap<>(5); /** * Default constructor. + * * @param multipartConfiguration The multipart configuration */ public UndertowConfiguration(@Nullable MultipartConfiguration multipartConfiguration) { this.multipartConfiguration = multipartConfiguration; } + /** + * @return The access log configuration. + */ + public Optional getAccessLogConfiguration() { + return Optional.ofNullable(accessLogConfiguration); + } + + /** + * The access log configuration. + * + * @param accessLogConfiguration Sets the access log configuration. + * @see AccessLogConfiguration + */ + @Inject + public void setAccessLogConfiguration(@Nullable AccessLogConfiguration accessLogConfiguration) { + this.accessLogConfiguration = accessLogConfiguration; + } + /** * @return The undertow builder */ @@ -83,12 +110,13 @@ public Map getWorkerOptions() { /** * Sets the worker options. + * * @param workerOptions The worker options */ public void setWorkerOptions( - @MapFormat(keyFormat = StringConvention.UNDER_SCORE_SEPARATED, - transformation = MapFormat.MapTransformation.FLAT) - Map workerOptions) { + @MapFormat(keyFormat = StringConvention.UNDER_SCORE_SEPARATED, + transformation = MapFormat.MapTransformation.FLAT) + Map workerOptions) { if (workerOptions != null) { this.workerOptions.putAll(workerOptions); } @@ -103,12 +131,13 @@ public Map getSocketOptions() { /** * Sets the socket options. + * * @param socketOptions The socket options */ public void setSocketOptions( - @MapFormat(keyFormat = StringConvention.UNDER_SCORE_SEPARATED, - transformation = MapFormat.MapTransformation.FLAT) - Map socketOptions) { + @MapFormat(keyFormat = StringConvention.UNDER_SCORE_SEPARATED, + transformation = MapFormat.MapTransformation.FLAT) + Map socketOptions) { if (socketOptions != null) { this.socketOptions.putAll(socketOptions); } @@ -125,11 +154,80 @@ public Map getServerOptions() { * @param serverOptions Sets the server options */ public void setServerOptions( - @MapFormat(keyFormat = StringConvention.UNDER_SCORE_SEPARATED, - transformation = MapFormat.MapTransformation.FLAT) - Map serverOptions) { + @MapFormat(keyFormat = StringConvention.UNDER_SCORE_SEPARATED, + transformation = MapFormat.MapTransformation.FLAT) + Map serverOptions) { if (serverOptions != null) { this.serverOptions.putAll(serverOptions); } } + + /** + * The access log configuration. + * + * @since 4.8.0 + */ + @ConfigurationProperties(AccessLogConfiguration.PREFIX) + @Requires(property = AccessLogConfiguration.ENABLED, value = StringUtils.TRUE) + public static class AccessLogConfiguration implements Toggleable { + + public static final String PREFIX = "access-log"; + + public static final String ENABLED = UndertowConfiguration.PREFIX + ".undertow." + PREFIX + ".enabled"; + + @ConfigurationBuilder(prefixes = "set", excludes = {"logFileHeaderGenerator", "logWriteExecutor"}) + DefaultAccessLogReceiver.Builder builder = DefaultAccessLogReceiver.builder(); + + private boolean enabled = true; + private String pattern = "common"; + + /** + * Default constructor. + * @param executorService The executor to use + */ + public AccessLogConfiguration(@Named(TaskExecutors.BLOCKING) ExecutorService executorService) { + // default to blocking executor. + builder.setLogWriteExecutor(executorService); + builder.setLogBaseName("access-"); + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + /** + * @param enabled Sets whether enabled. + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + /** + * @return The log pattern to use. + */ + public String getPattern() { + return pattern; + } + + /** + * Sets the underlow log pattern. + * + *

See https://undertow.io/javadoc/1.4.x/io/undertow/server/handlers/accesslog/AccessLogHandler.html for more.

+ * + * @param pattern The pattern + */ + public void setPattern(String pattern) { + if (StringUtils.isNotEmpty(pattern)) { + this.pattern = pattern; + } + } + + /** + * @return The log receiver builder. + */ + public DefaultAccessLogReceiver.Builder getBuilder() { + return builder; + } + } } diff --git a/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowFactory.java b/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowFactory.java index f57845444..0727ca403 100644 --- a/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowFactory.java +++ b/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowFactory.java @@ -33,7 +33,8 @@ import io.undertow.Handlers; import io.undertow.Undertow; import io.undertow.UndertowOptions; -import io.undertow.server.handlers.PathHandler; +import io.undertow.server.HttpHandler; +import io.undertow.server.handlers.accesslog.AccessLogHandler; import io.undertow.servlet.Servlets; import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentManager; @@ -82,6 +83,11 @@ public UndertowFactory( this.router = applicationContext.findBean(Router.class).orElse(null); } + @Override + public UndertowConfiguration getServerConfiguration() { + return (UndertowConfiguration) super.getServerConfiguration(); + } + /** * The undertow builder bean. * @@ -101,14 +107,24 @@ protected Undertow.Builder undertowBuilder(DeploymentInfo deploymentInfo, Micron final DeploymentManager deploymentManager = Servlets.defaultContainer().addDeployment(deploymentInfo); deploymentManager .deploy(); - PathHandler path; + HttpHandler httpHandler; try { - path = Handlers.path(Handlers.redirect(cp)) + httpHandler = Handlers.path(Handlers.redirect(cp)) .addPrefixPath(cp, deploymentManager.start()); } catch (ServletException e) { throw new ServerStartupException("Error starting Undertow server: " + e.getMessage(), e); } - builder.setHandler(path); + UndertowConfiguration serverConfiguration = getServerConfiguration(); + UndertowConfiguration.AccessLogConfiguration accessLogConfiguration = serverConfiguration.getAccessLogConfiguration().orElse(null); + if (accessLogConfiguration != null) { + httpHandler = new AccessLogHandler( + httpHandler, + accessLogConfiguration.builder.build(), + accessLogConfiguration.getPattern(), + getApplicationContext().getClassLoader() + ); + } + builder.setHandler(httpHandler); final SslConfiguration sslConfiguration = getSslConfiguration(); if (sslConfiguration.isEnabled()) { @@ -261,9 +277,9 @@ protected DeploymentInfo deploymentInfo(MicronautServletConfiguration servletCon final String cp = getContextPath(); for (ServletContainerInitializer servletInitializer : servletInitializers) { if (servletInitializer instanceof MicronautServletInitializer micronautServletInitializer) { - getStaticResourceConfigurations().forEach(config -> { - micronautServletInitializer.addMicronautServletMapping(config.getMapping()); - }); + getStaticResourceConfigurations().forEach(config -> + micronautServletInitializer.addMicronautServletMapping(config.getMapping()) + ); } } DeploymentInfo deploymentInfo = Servlets.deployment() diff --git a/http-server-undertow/src/test/groovy/io/micronaut/servlet/undertow/UndertowAccessLogSpec.groovy b/http-server-undertow/src/test/groovy/io/micronaut/servlet/undertow/UndertowAccessLogSpec.groovy new file mode 100644 index 000000000..3440245f6 --- /dev/null +++ b/http-server-undertow/src/test/groovy/io/micronaut/servlet/undertow/UndertowAccessLogSpec.groovy @@ -0,0 +1,59 @@ +package io.micronaut.servlet.undertow + +import io.micronaut.context.annotation.Requires +import io.micronaut.context.annotation.Value +import io.micronaut.http.annotation.Controller +import io.micronaut.http.annotation.Get +import io.micronaut.http.client.HttpClient +import io.micronaut.http.client.annotation.Client +import io.micronaut.servlet.undertow.UndertowConfiguration.AccessLogConfiguration +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import io.micronaut.test.support.TestPropertyProvider +import io.undertow.Undertow +import io.undertow.server.handlers.accesslog.AccessLogHandler +import jakarta.inject.Inject +import spock.lang.Specification + +import java.nio.file.Files + +@MicronautTest +class UndertowAccessLogSpec extends Specification implements TestPropertyProvider { + @Inject AccessLogConfiguration accessLogConfiguration + @Inject Undertow undertow + @Inject + @Client("/") + HttpClient rxClient + + @Value("\${micronaut.server.undertow.access-log.output-directory}") + String log + + void 'test access log configuration'() { + expect: + accessLogConfiguration + accessLogConfiguration.pattern == 'combined' + undertow != null + undertow.listenerInfo[0].openListener.rootHandler instanceof AccessLogHandler + rxClient.toBlocking().retrieve("/log-me") == 'ok' + new File(log, "access-log").exists() + new File(log, "access-log").text + } + + @Override + Map getProperties() { + return [ + 'spec.name':'UndertowAccessLogSpec', + "micronaut.server.undertow.access-log.enabled": true, + "micronaut.server.undertow.access-log.pattern": "combined", + "micronaut.server.undertow.access-log.output-directory": Files.createTempDirectory("test-log").toAbsolutePath().toString() + ] + } + + @Controller('/log-me') + @Requires(property = "spec.name", value = 'UndertowAccessLogSpec') + static class LogTestController { + @Get(produces = "text/plain") + String go() { + return "ok"; + } + } +} From 1bad20ee761f21618f38b176087ead7eac6d53d7 Mon Sep 17 00:00:00 2001 From: Graeme Rocher Date: Tue, 28 May 2024 17:19:39 +0200 Subject: [PATCH 3/4] try fix tests --- .../servlet/undertow/UndertowAccessLogSpec.groovy | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/http-server-undertow/src/test/groovy/io/micronaut/servlet/undertow/UndertowAccessLogSpec.groovy b/http-server-undertow/src/test/groovy/io/micronaut/servlet/undertow/UndertowAccessLogSpec.groovy index 3440245f6..09368b4a8 100644 --- a/http-server-undertow/src/test/groovy/io/micronaut/servlet/undertow/UndertowAccessLogSpec.groovy +++ b/http-server-undertow/src/test/groovy/io/micronaut/servlet/undertow/UndertowAccessLogSpec.groovy @@ -13,6 +13,7 @@ import io.undertow.Undertow import io.undertow.server.handlers.accesslog.AccessLogHandler import jakarta.inject.Inject import spock.lang.Specification +import spock.util.concurrent.PollingConditions import java.nio.file.Files @@ -28,14 +29,19 @@ class UndertowAccessLogSpec extends Specification implements TestPropertyProvide String log void 'test access log configuration'() { + given: + PollingConditions pollingConditions = new PollingConditions(timeout: 20) expect: accessLogConfiguration accessLogConfiguration.pattern == 'combined' undertow != null undertow.listenerInfo[0].openListener.rootHandler instanceof AccessLogHandler rxClient.toBlocking().retrieve("/log-me") == 'ok' - new File(log, "access-log").exists() - new File(log, "access-log").text + pollingConditions.eventually { + assert new File(log, "access-log").exists() + assert new File(log, "access-log").text + } + } @Override From 209aedb2dfba41cfcea1a1b0b09d5481312e157b Mon Sep 17 00:00:00 2001 From: Graeme Rocher Date: Tue, 28 May 2024 17:25:48 +0200 Subject: [PATCH 4/4] sonar --- .../java/io/micronaut/servlet/jetty/JettyConfiguration.java | 4 ++-- .../io/micronaut/servlet/tomcat/TomcatConfiguration.java | 5 +++-- .../io/micronaut/servlet/undertow/UndertowConfiguration.java | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyConfiguration.java b/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyConfiguration.java index 939b279ff..4d04c5b5f 100644 --- a/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyConfiguration.java +++ b/http-server-jetty/src/main/java/io/micronaut/servlet/jetty/JettyConfiguration.java @@ -129,10 +129,10 @@ public static class JettySslConfiguration extends SecureRequestCustomizer { * @since 4.8.0 */ @ConfigurationProperties(JettyRequestLog.ACCESS_LOG) - @Requires(property = JettyRequestLog.ENABLED, value = StringUtils.TRUE) + @Requires(property = JettyRequestLog.ENABLED_PROPERTY, value = StringUtils.TRUE) public static class JettyRequestLog implements Toggleable { public static final String ACCESS_LOG = "access-log"; - public static final String ENABLED = JettyConfiguration.PREFIX + ".jetty." + ACCESS_LOG + ".enabled"; + public static final String ENABLED_PROPERTY = HttpServerConfiguration.PREFIX + ".jetty." + ACCESS_LOG + ".enabled"; @ConfigurationBuilder(prefixes = "set", excludes = "eventListeners") RequestLogWriter requestLogWriter = new RequestLogWriter(); diff --git a/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatConfiguration.java b/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatConfiguration.java index fa646c4af..bf20c099b 100644 --- a/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatConfiguration.java +++ b/http-server-tomcat/src/main/java/io/micronaut/servlet/tomcat/TomcatConfiguration.java @@ -127,12 +127,13 @@ public void setAccessLogConfiguration(@Nullable AccessLogConfiguration accessLog * @since 4.8.0 */ @ConfigurationProperties(value = AccessLogConfiguration.PREFIX, excludes = {"next", "container"}) - @Requires(property = AccessLogConfiguration.ENABLED, value = StringUtils.TRUE) + @Requires(property = AccessLogConfiguration.ENABLED_PROPERTY, value = StringUtils.TRUE) + @SuppressWarnings("java:S110") public static class AccessLogConfiguration extends ExtendedAccessLogValve implements Toggleable { public static final String PREFIX = "access-log"; - public static final String ENABLED = TomcatConfiguration.PREFIX + ".tomcat." + PREFIX + ".enabled"; + public static final String ENABLED_PROPERTY = HttpServerConfiguration.PREFIX + ".tomcat." + PREFIX + ".enabled"; @Override public boolean isEnabled() { diff --git a/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowConfiguration.java b/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowConfiguration.java index 77f0f58b0..ed0f1dee3 100644 --- a/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowConfiguration.java +++ b/http-server-undertow/src/main/java/io/micronaut/servlet/undertow/UndertowConfiguration.java @@ -168,12 +168,12 @@ public void setServerOptions( * @since 4.8.0 */ @ConfigurationProperties(AccessLogConfiguration.PREFIX) - @Requires(property = AccessLogConfiguration.ENABLED, value = StringUtils.TRUE) + @Requires(property = AccessLogConfiguration.ENABLED_PROPERTY, value = StringUtils.TRUE) public static class AccessLogConfiguration implements Toggleable { public static final String PREFIX = "access-log"; - public static final String ENABLED = UndertowConfiguration.PREFIX + ".undertow." + PREFIX + ".enabled"; + public static final String ENABLED_PROPERTY = HttpServerConfiguration.PREFIX + ".undertow." + PREFIX + ".enabled"; @ConfigurationBuilder(prefixes = "set", excludes = {"logFileHeaderGenerator", "logWriteExecutor"}) DefaultAccessLogReceiver.Builder builder = DefaultAccessLogReceiver.builder();