Write management and main server access logs to separate files
Previously, when access logging was enabled and the management server was running on a separate port, both the main server and the management server would write their access logs to the same file. Having two separate containers writing to the same file could cause problems such as causing log rotation to break. This commit updates the actuator so that when the management server is running on a separate port (and therefore using a separate container) it prepends management_ to the access log prefix so that the main server and the management server write their access logs to separate files in the same directory. Closes gh-6618
This commit is contained in:
@@ -307,6 +307,22 @@
|
||||
<artifactId>json-path</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-servlet</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
|
||||
@@ -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<T extends EmbeddedServletContainerFactory>
|
||||
implements EmbeddedServletContainerCustomizer, Ordered {
|
||||
|
||||
private final Class<T> factoryClass;
|
||||
|
||||
AccessLogCustomizer(Class<T> 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<TomcatEmbeddedServletContainerFactory> {
|
||||
|
||||
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<UndertowEmbeddedServletContainerFactory> {
|
||||
|
||||
UndertowAccessLogCustomizer() {
|
||||
super(UndertowEmbeddedServletContainerFactory.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(UndertowEmbeddedServletContainerFactory container) {
|
||||
container.setAccessLogPrefix(customizePrefix(container.getAccessLogPrefix()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<? extends MvcEndpoint> 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 {
|
||||
|
||||
@@ -568,6 +568,10 @@ public class UndertowEmbeddedServletContainerFactory
|
||||
this.accessLogPattern = accessLogPattern;
|
||||
}
|
||||
|
||||
public String getAccessLogPrefix() {
|
||||
return this.accessLogPrefix;
|
||||
}
|
||||
|
||||
public void setAccessLogPrefix(String accessLogPrefix) {
|
||||
this.accessLogPrefix = accessLogPrefix;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user