diff --git a/spring-boot-actuator/pom.xml b/spring-boot-actuator/pom.xml index 8863c7c4df..84bc130139 100644 --- a/spring-boot-actuator/pom.xml +++ b/spring-boot-actuator/pom.xml @@ -307,6 +307,22 @@ json-path test + + io.undertow + undertow-core + test + + + io.undertow + undertow-servlet + test + + + org.jboss.spec.javax.servlet + jboss-servlet-api_3.1_spec + + + org.aspectj aspectjrt diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java index a61a32dceb..b4a8ef2998 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java @@ -24,6 +24,9 @@ import javax.servlet.Filter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.catalina.Valve; +import org.apache.catalina.valves.AccessLogValve; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.HierarchicalBeanFactory; @@ -43,6 +46,9 @@ import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; import org.springframework.boot.context.embedded.EmbeddedServletContainer; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; +import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory; import org.springframework.boot.web.servlet.ErrorPage; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -106,6 +112,17 @@ public class EndpointWebMvcChildContextConfiguration { return new ServerCustomization(); } + @Bean + public UndertowAccessLogCustomizer undertowAccessLogCustomizer() { + return new UndertowAccessLogCustomizer(); + } + + @Bean + @ConditionalOnClass(name = "org.apache.catalina.valves.AccessLogValve") + public TomcatAccessLogCustomizer tomcatAccessLogCustomizer() { + return new TomcatAccessLogCustomizer(); + } + /* * The error controller is present but not mapped as an endpoint in this context * because of the DispatcherServlet having had its HandlerMapping explicitly disabled. @@ -321,4 +338,79 @@ public class EndpointWebMvcChildContextConfiguration { } + static abstract class AccessLogCustomizer + implements EmbeddedServletContainerCustomizer, Ordered { + + private final Class factoryClass; + + AccessLogCustomizer(Class factoryClass) { + this.factoryClass = factoryClass; + } + + protected String customizePrefix(String prefix) { + return "management_" + prefix; + } + + @Override + public int getOrder() { + return 1; + } + + @Override + public void customize(ConfigurableEmbeddedServletContainer container) { + if (this.factoryClass.isInstance(container)) { + customize(this.factoryClass.cast(container)); + } + } + + abstract void customize(T container); + } + + static class TomcatAccessLogCustomizer + extends AccessLogCustomizer { + + TomcatAccessLogCustomizer() { + super(TomcatEmbeddedServletContainerFactory.class); + } + + @Override + public int getOrder() { + return 1; + } + + @Override + public void customize(TomcatEmbeddedServletContainerFactory container) { + AccessLogValve accessLogValve = findAccessLogValve(container); + if (accessLogValve == null) { + return; + } + accessLogValve.setPrefix(customizePrefix(accessLogValve.getPrefix())); + } + + private AccessLogValve findAccessLogValve( + TomcatEmbeddedServletContainerFactory container) { + for (Valve engineValve : container.getEngineValves()) { + if (engineValve instanceof AccessLogValve) { + return (AccessLogValve) engineValve; + } + } + return null; + } + + } + + static class UndertowAccessLogCustomizer + extends AccessLogCustomizer { + + UndertowAccessLogCustomizer() { + super(UndertowEmbeddedServletContainerFactory.class); + } + + @Override + public void customize(UndertowEmbeddedServletContainerFactory container) { + container.setAccessLogPrefix(customizePrefix(container.getAccessLogPrefix())); + } + + } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java index 4ce12702fc..09a10ca285 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java @@ -29,6 +29,8 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.catalina.Valve; +import org.apache.catalina.valves.AccessLogValve; import org.apache.http.client.HttpClient; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; @@ -67,6 +69,7 @@ import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent; import org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory; import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.testutil.Matched; @@ -429,7 +432,8 @@ public class EndpointWebMvcAutoConfigurationTests { this.applicationContext.register(RootConfig.class, BaseConfiguration.class, ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); this.applicationContext.refresh(); - // /health, /metrics, /env, /actuator, /heapdump (/shutdown is disabled by default) + // /health, /metrics, /env, /actuator, /heapdump (/shutdown is disabled by + // default) assertThat(this.applicationContext.getBeansOfType(MvcEndpoint.class)).hasSize(5); } @@ -562,6 +566,54 @@ public class EndpointWebMvcAutoConfigurationTests { assertThat(managementServerProperties.getSsl().isEnabled()).isFalse(); } + @Test + public void tomcatManagementAccessLogUsesCustomPrefix() throws Exception { + this.applicationContext.register(TomcatContainerConfig.class, RootConfig.class, + EndpointConfig.class, DifferentPortConfig.class, BaseConfiguration.class, + EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(this.applicationContext, + "server.tomcat.accesslog.enabled: true"); + this.applicationContext.refresh(); + ApplicationContext managementContext = this.applicationContext + .getBean(ManagementContextResolver.class).getApplicationContext(); + EmbeddedServletContainerFactory servletContainerFactory = managementContext + .getBean(EmbeddedServletContainerFactory.class); + assertThat(servletContainerFactory) + .isInstanceOf(TomcatEmbeddedServletContainerFactory.class); + AccessLogValve accessLogValve = findAccessLogValve( + ((TomcatEmbeddedServletContainerFactory) servletContainerFactory)); + assertThat(accessLogValve).isNotNull(); + assertThat(accessLogValve.getPrefix()).isEqualTo("management_access_log"); + } + + @Test + public void undertowManagementAccessLogUsesCustomPrefix() throws Exception { + this.applicationContext.register(UndertowContainerConfig.class, RootConfig.class, + EndpointConfig.class, DifferentPortConfig.class, BaseConfiguration.class, + EndpointWebMvcAutoConfiguration.class, ErrorMvcAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(this.applicationContext, + "server.undertow.accesslog.enabled: true"); + this.applicationContext.refresh(); + ApplicationContext managementContext = this.applicationContext + .getBean(ManagementContextResolver.class).getApplicationContext(); + EmbeddedServletContainerFactory servletContainerFactory = managementContext + .getBean(EmbeddedServletContainerFactory.class); + assertThat(servletContainerFactory) + .isInstanceOf(UndertowEmbeddedServletContainerFactory.class); + assertThat(((UndertowEmbeddedServletContainerFactory) servletContainerFactory) + .getAccessLogPrefix()).isEqualTo("management_access_log."); + } + + private AccessLogValve findAccessLogValve( + TomcatEmbeddedServletContainerFactory container) { + for (Valve engineValve : container.getEngineValves()) { + if (engineValve instanceof AccessLogValve) { + return (AccessLogValve) engineValve; + } + } + return null; + } + private void endpointDisabled(String name, Class type) { this.applicationContext.register(RootConfig.class, BaseConfiguration.class, ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class); @@ -734,6 +786,26 @@ public class EndpointWebMvcAutoConfigurationTests { } + @Configuration + public static class TomcatContainerConfig { + + @Bean + public TomcatEmbeddedServletContainerFactory embeddedServletContainerFactory() { + return new TomcatEmbeddedServletContainerFactory(); + } + + } + + @Configuration + public static class UndertowContainerConfig { + + @Bean + public UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory() { + return new UndertowEmbeddedServletContainerFactory(); + } + + } + @Configuration @Import(ServerPortConfig.class) public static class DifferentPortConfig { diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java index e868383866..fd06f59390 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java @@ -568,6 +568,10 @@ public class UndertowEmbeddedServletContainerFactory this.accessLogPattern = accessLogPattern; } + public String getAccessLogPrefix() { + return this.accessLogPrefix; + } + public void setAccessLogPrefix(String accessLogPrefix) { this.accessLogPrefix = accessLogPrefix; }