diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 0f09c85204..7e63016ac6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -546,6 +546,18 @@ public class ServerProperties { */ private boolean enabled = false; + /** + * Whether logging of the request will only be enabled if + * "ServletRequest.getAttribute(conditionIf)" does not yield null. + */ + private String conditionIf; + + /** + * Whether logging of the request will only be enabled if + * "ServletRequest.getAttribute(conditionUnless)" yield null. + */ + private String conditionUnless; + /** * Format pattern for access logs. */ @@ -567,6 +579,24 @@ public class ServerProperties { */ private String suffix = ".log"; + /** + * Character set used by the log file. Default to the system default character + * set. + */ + private String encoding; + + /** + * Locale used to format timestamps in log entries and in log file name + * suffix. Default to the default locale of the Java process. + */ + private String locale; + + /** + * Whether to check for log file existence so it can be recreated it if an + * external process has renamed it. + */ + private boolean checkExists = false; + /** * Whether to enable access log rotation. */ @@ -588,6 +618,11 @@ public class ServerProperties { */ private String fileDateFormat = ".yyyy-MM-dd"; + /** + * Whether to use IPv6 canonical representation format as defined by RFC 5952. + */ + private boolean ipv6Canonical = false; + /** * Set request attributes for the IP address, Hostname, protocol, and port * used for the request. @@ -599,42 +634,6 @@ public class ServerProperties { */ private boolean buffered = true; - /** - * Check for log file existence so it can be recreated it if an external - * process/agent has renamed it. - */ - private boolean checkExists = false; - - /** - * If the value returned from ServletRequest.getAttribute(conditionIf) yields - * a null value, logging of the request will be skipped. - */ - private String conditionIf; - - /** - * If the value returned from ServletRequest.getAttribute(conditionUnless) - * yields a non-null value, the logging of the request will be skipped. - */ - private String conditionUnless; - - /** - * Character set used by the log file. If it is null, the system - * default character set will be used. An empty string will be treated as - * null when this property is assigned. - */ - private String encoding; - - /** - * Use IPv6 canonical representation format as defined by RFC 5952 in output. - */ - private boolean ipv6Canonical = false; - - /** - * Set the locale used to format timestamps in log entries and in log file - * name suffix. - */ - private String locale = Locale.getDefault().toString(); - public boolean isEnabled() { return this.enabled; } @@ -643,6 +642,22 @@ public class ServerProperties { this.enabled = enabled; } + public String getConditionIf() { + return this.conditionIf; + } + + public void setConditionIf(String conditionIf) { + this.conditionIf = conditionIf; + } + + public String getConditionUnless() { + return this.conditionUnless; + } + + public void setConditionUnless(String conditionUnless) { + this.conditionUnless = conditionUnless; + } + public String getPattern() { return this.pattern; } @@ -675,6 +690,30 @@ public class ServerProperties { this.suffix = suffix; } + public String getEncoding() { + return this.encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public String getLocale() { + return this.locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + + public boolean isCheckExists() { + return this.checkExists; + } + + public void setCheckExists(boolean checkExists) { + this.checkExists = checkExists; + } + public boolean isRotate() { return this.rotate; } @@ -707,6 +746,14 @@ public class ServerProperties { this.fileDateFormat = fileDateFormat; } + public boolean isIpv6Canonical() { + return this.ipv6Canonical; + } + + public void setIpv6Canonical(boolean ipv6Canonical) { + this.ipv6Canonical = ipv6Canonical; + } + public boolean isRequestAttributesEnabled() { return this.requestAttributesEnabled; } @@ -723,54 +770,6 @@ public class ServerProperties { this.buffered = buffered; } - public boolean isCheckExists() { - return this.checkExists; - } - - public void setCheckExists(boolean checkExists) { - this.checkExists = checkExists; - } - - public String getConditionIf() { - return this.conditionIf; - } - - public void setConditionIf(String conditionIf) { - this.conditionIf = conditionIf; - } - - public String getConditionUnless() { - return this.conditionUnless; - } - - public void setConditionUnless(String conditionUnless) { - this.conditionUnless = conditionUnless; - } - - public String getEncoding() { - return this.encoding; - } - - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - public boolean isIpv6Canonical() { - return this.ipv6Canonical; - } - - public void setIpv6Canonical(boolean ipv6Canonical) { - this.ipv6Canonical = ipv6Canonical; - } - - public String getLocale() { - return this.locale; - } - - public void setLocale(String locale) { - this.locale = locale; - } - } /** diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index e674a8d22c..76cba0c862 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -30,6 +30,7 @@ import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat; +import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Accesslog; import org.springframework.boot.cloud.CloudPlatform; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory; @@ -247,23 +248,25 @@ public class TomcatWebServerFactoryCustomizer implements private void customizeAccessLog(ConfigurableTomcatWebServerFactory factory) { ServerProperties.Tomcat tomcatProperties = this.serverProperties.getTomcat(); AccessLogValve valve = new AccessLogValve(); - valve.setPattern(tomcatProperties.getAccesslog().getPattern()); - valve.setDirectory(tomcatProperties.getAccesslog().getDirectory()); - valve.setPrefix(tomcatProperties.getAccesslog().getPrefix()); - valve.setSuffix(tomcatProperties.getAccesslog().getSuffix()); - valve.setRenameOnRotate(tomcatProperties.getAccesslog().isRenameOnRotate()); - valve.setMaxDays(tomcatProperties.getAccesslog().getMaxDays()); - valve.setFileDateFormat(tomcatProperties.getAccesslog().getFileDateFormat()); - valve.setRequestAttributesEnabled( - tomcatProperties.getAccesslog().isRequestAttributesEnabled()); - valve.setRotatable(tomcatProperties.getAccesslog().isRotate()); - valve.setBuffered(tomcatProperties.getAccesslog().isBuffered()); - valve.setCheckExists(tomcatProperties.getAccesslog().isCheckExists()); - valve.setConditionIf(tomcatProperties.getAccesslog().getConditionIf()); - valve.setConditionUnless(tomcatProperties.getAccesslog().getConditionUnless()); - valve.setEncoding(tomcatProperties.getAccesslog().getEncoding()); - valve.setIpv6Canonical(tomcatProperties.getAccesslog().isIpv6Canonical()); - valve.setLocale(tomcatProperties.getAccesslog().getLocale()); + PropertyMapper map = PropertyMapper.get(); + Accesslog accessLogConfig = tomcatProperties.getAccesslog(); + map.from(accessLogConfig.getConditionIf()).to(valve::setConditionIf); + map.from(accessLogConfig.getConditionUnless()).to(valve::setConditionUnless); + map.from(accessLogConfig.getPattern()).to(valve::setPattern); + map.from(accessLogConfig.getDirectory()).to(valve::setDirectory); + map.from(accessLogConfig.getPrefix()).to(valve::setPrefix); + map.from(accessLogConfig.getSuffix()).to(valve::setSuffix); + map.from(accessLogConfig.getEncoding()).whenHasText().to(valve::setEncoding); + map.from(accessLogConfig.getLocale()).whenHasText().to(valve::setLocale); + map.from(accessLogConfig.isCheckExists()).to(valve::setCheckExists); + map.from(accessLogConfig.isRotate()).to(valve::setRotatable); + map.from(accessLogConfig.isRenameOnRotate()).to(valve::setRenameOnRotate); + map.from(accessLogConfig.getMaxDays()).to(valve::setMaxDays); + map.from(accessLogConfig.getFileDateFormat()).to(valve::setFileDateFormat); + map.from(accessLogConfig.isIpv6Canonical()).to(valve::setIpv6Canonical); + map.from(accessLogConfig.isRequestAttributesEnabled()) + .to(valve::setRequestAttributesEnabled); + map.from(accessLogConfig.isBuffered()).to(valve::setBuffered); factory.addEngineValves(valve); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index 397244ac80..df2eaf5ec0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -42,6 +42,7 @@ import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.Request; import org.junit.Test; +import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Accesslog; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.source.ConfigurationPropertySource; @@ -112,36 +113,37 @@ public class ServerPropertiesTests { @Test public void testTomcatBinding() { Map map = new HashMap<>(); - map.put("server.tomcat.accesslog.pattern", "%h %t '%r' %s %b"); - map.put("server.tomcat.accesslog.prefix", "foo"); - map.put("server.tomcat.accesslog.rotate", "false"); - map.put("server.tomcat.accesslog.rename-on-rotate", "true"); - map.put("server.tomcat.accesslog.request-attributes-enabled", "true"); - map.put("server.tomcat.accesslog.suffix", "-bar.log"); - map.put("server.tomcat.accesslog.checkExists", "true"); map.put("server.tomcat.accesslog.conditionIf", "foo"); map.put("server.tomcat.accesslog.conditionUnless", "bar"); + map.put("server.tomcat.accesslog.pattern", "%h %t '%r' %s %b"); + map.put("server.tomcat.accesslog.prefix", "foo"); + map.put("server.tomcat.accesslog.suffix", "-bar.log"); map.put("server.tomcat.accesslog.encoding", "UTF-8"); - map.put("server.tomcat.accesslog.ipv6Canonical", "true"); map.put("server.tomcat.accesslog.locale", "en-AU"); + map.put("server.tomcat.accesslog.checkExists", "true"); + map.put("server.tomcat.accesslog.rotate", "false"); + map.put("server.tomcat.accesslog.rename-on-rotate", "true"); + map.put("server.tomcat.accesslog.ipv6Canonical", "true"); + map.put("server.tomcat.accesslog.request-attributes-enabled", "true"); map.put("server.tomcat.protocol-header", "X-Forwarded-Protocol"); map.put("server.tomcat.remote-ip-header", "Remote-Ip"); map.put("server.tomcat.internal-proxies", "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); map.put("server.tomcat.background-processor-delay", "10"); bind(map); ServerProperties.Tomcat tomcat = this.properties.getTomcat(); - assertThat(tomcat.getAccesslog().getPattern()).isEqualTo("%h %t '%r' %s %b"); - assertThat(tomcat.getAccesslog().getPrefix()).isEqualTo("foo"); - assertThat(tomcat.getAccesslog().isRotate()).isFalse(); - assertThat(tomcat.getAccesslog().isRenameOnRotate()).isTrue(); - assertThat(tomcat.getAccesslog().isRequestAttributesEnabled()).isTrue(); - assertThat(tomcat.getAccesslog().getSuffix()).isEqualTo("-bar.log"); - assertThat(tomcat.getAccesslog().isCheckExists()).isEqualTo(true); - assertThat(tomcat.getAccesslog().getConditionIf()).isEqualTo("foo"); - assertThat(tomcat.getAccesslog().getConditionUnless()).isEqualTo("bar"); - assertThat(tomcat.getAccesslog().getEncoding()).isEqualTo("UTF-8"); - assertThat(tomcat.getAccesslog().isIpv6Canonical()).isTrue(); - assertThat(tomcat.getAccesslog().getLocale()).isEqualTo("en-AU"); + Accesslog accesslog = tomcat.getAccesslog(); + assertThat(accesslog.getConditionIf()).isEqualTo("foo"); + assertThat(accesslog.getConditionUnless()).isEqualTo("bar"); + assertThat(accesslog.getPattern()).isEqualTo("%h %t '%r' %s %b"); + assertThat(accesslog.getPrefix()).isEqualTo("foo"); + assertThat(accesslog.getSuffix()).isEqualTo("-bar.log"); + assertThat(accesslog.getEncoding()).isEqualTo("UTF-8"); + assertThat(accesslog.getLocale()).isEqualTo("en-AU"); + assertThat(accesslog.isCheckExists()).isEqualTo(true); + assertThat(accesslog.isRotate()).isFalse(); + assertThat(accesslog.isRenameOnRotate()).isTrue(); + assertThat(accesslog.isIpv6Canonical()).isTrue(); + assertThat(accesslog.isRequestAttributesEnabled()).isTrue(); assertThat(tomcat.getRemoteIpHeader()).isEqualTo("Remote-Ip"); assertThat(tomcat.getProtocolHeader()).isEqualTo("X-Forwarded-Protocol"); assertThat(tomcat.getInternalProxies()) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index 032e700743..12ee998d54 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -326,32 +326,6 @@ public class TomcatWebServerFactoryCustomizerTests { this.serverProperties.getTomcat().getAccesslog().getMaxDays()); } - @Test - public void accessLogMaxDaysCanBeRedefined() { - bind("server.tomcat.accesslog.enabled=true", - "server.tomcat.accesslog.max-days=20"); - TomcatServletWebServerFactory factory = customizeAndGetFactory(); - assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) - .getMaxDays()).isEqualTo(20); - } - - @Test - public void accessLogCheckExistsDefault() { - bind("server.tomcat.accesslog.enabled=true"); - TomcatServletWebServerFactory factory = customizeAndGetFactory(); - assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) - .isCheckExists()).isFalse(); - } - - @Test - public void accessLogCheckExistsSpecified() { - bind("server.tomcat.accesslog.enabled=true", - "server.tomcat.accesslog.checkExists=true"); - TomcatServletWebServerFactory factory = customizeAndGetFactory(); - assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) - .isCheckExists()).isTrue(); - } - @Test public void accessLogConditionCanBeSpecified() { bind("server.tomcat.accesslog.enabled=true", @@ -385,23 +359,6 @@ public class TomcatWebServerFactoryCustomizerTests { .getEncoding()).isEqualTo("UTF-8"); } - @Test - public void accessLogDoesNotUseIpv6CanonicalFormatByDefault() { - bind("server.tomcat.accesslog.enabled=true"); - TomcatServletWebServerFactory factory = customizeAndGetFactory(); - assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) - .getIpv6Canonical()).isFalse(); - } - - @Test - public void accessLogwithIpv6CanonicalSet() { - bind("server.tomcat.accesslog.enabled=true", - "server.tomcat.accesslog.ipv6Canonical=true"); - TomcatServletWebServerFactory factory = customizeAndGetFactory(); - assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) - .getIpv6Canonical()).isTrue(); - } - @Test public void accessLogWithDefaultLocale() { bind("server.tomcat.accesslog.enabled=true"); @@ -421,6 +378,49 @@ public class TomcatWebServerFactoryCustomizerTests { .getLocale()).isEqualTo(locale); } + @Test + public void accessLogCheckExistsDefault() { + bind("server.tomcat.accesslog.enabled=true"); + TomcatServletWebServerFactory factory = customizeAndGetFactory(); + assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) + .isCheckExists()).isFalse(); + } + + @Test + public void accessLogCheckExistsSpecified() { + bind("server.tomcat.accesslog.enabled=true", + "server.tomcat.accesslog.check-exists=true"); + TomcatServletWebServerFactory factory = customizeAndGetFactory(); + assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) + .isCheckExists()).isTrue(); + } + + @Test + public void accessLogMaxDaysCanBeRedefined() { + bind("server.tomcat.accesslog.enabled=true", + "server.tomcat.accesslog.max-days=20"); + TomcatServletWebServerFactory factory = customizeAndGetFactory(); + assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) + .getMaxDays()).isEqualTo(20); + } + + @Test + public void accessLogDoesNotUseIpv6CanonicalFormatByDefault() { + bind("server.tomcat.accesslog.enabled=true"); + TomcatServletWebServerFactory factory = customizeAndGetFactory(); + assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) + .getIpv6Canonical()).isFalse(); + } + + @Test + public void accessLogwithIpv6CanonicalSet() { + bind("server.tomcat.accesslog.enabled=true", + "server.tomcat.accesslog.ipv6-canonical=true"); + TomcatServletWebServerFactory factory = customizeAndGetFactory(); + assertThat(((AccessLogValve) factory.getEngineValves().iterator().next()) + .getIpv6Canonical()).isTrue(); + } + private void bind(String... inlinedProperties) { TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, inlinedProperties);