Commit 2bb7a430 authored by Phillip Webb's avatar Phillip Webb Committed by Andy Wilkinson

Clean up access logging threads when Undertow is stopped

Closes gh-12742
parent e7b03f7c
...@@ -32,6 +32,7 @@ import java.util.ArrayList; ...@@ -32,6 +32,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.EventListener;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
...@@ -46,6 +47,8 @@ import javax.net.ssl.TrustManagerFactory; ...@@ -46,6 +47,8 @@ import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509ExtendedKeyManager;
import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import io.undertow.Undertow; import io.undertow.Undertow;
...@@ -64,6 +67,7 @@ import io.undertow.server.session.SessionManager; ...@@ -64,6 +67,7 @@ import io.undertow.server.session.SessionManager;
import io.undertow.servlet.Servlets; import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.DeploymentManager; import io.undertow.servlet.api.DeploymentManager;
import io.undertow.servlet.api.ListenerInfo;
import io.undertow.servlet.api.MimeMapping; import io.undertow.servlet.api.MimeMapping;
import io.undertow.servlet.api.ServletContainerInitializerInfo; import io.undertow.servlet.api.ServletContainerInitializerInfo;
import io.undertow.servlet.api.ServletStackTraces; import io.undertow.servlet.api.ServletStackTraces;
...@@ -417,34 +421,41 @@ public class UndertowEmbeddedServletContainerFactory ...@@ -417,34 +421,41 @@ public class UndertowEmbeddedServletContainerFactory
} }
private void configureAccessLog(DeploymentInfo deploymentInfo) { private void configureAccessLog(DeploymentInfo deploymentInfo) {
deploymentInfo.addInitialHandlerChainWrapper(new HandlerWrapper() {
@Override
public HttpHandler wrap(HttpHandler handler) {
return createAccessLogHandler(handler);
}
});
}
private AccessLogHandler createAccessLogHandler(HttpHandler handler) {
try { try {
createAccessLogDirectoryIfNecessary(); createAccessLogDirectoryIfNecessary();
XnioWorker worker = createWorker();
String prefix = (this.accessLogPrefix != null ? this.accessLogPrefix String prefix = (this.accessLogPrefix != null ? this.accessLogPrefix
: "access_log."); : "access_log.");
AccessLogReceiver accessLogReceiver = new DefaultAccessLogReceiver( DefaultAccessLogReceiver accessLogReceiver = new DefaultAccessLogReceiver(
createWorker(), this.accessLogDirectory, prefix, this.accessLogSuffix, worker, this.accessLogDirectory, prefix, this.accessLogSuffix,
this.accessLogRotate); this.accessLogRotate);
String formatString = (this.accessLogPattern != null ? this.accessLogPattern EventListener listener = new AccessLogShutdownListener(worker,
: "common"); accessLogReceiver);
return new AccessLogHandler(handler, accessLogReceiver, formatString, deploymentInfo.addListener(new ListenerInfo(AccessLogShutdownListener.class,
Undertow.class.getClassLoader()); new ImmediateInstanceFactory<EventListener>(listener)));
deploymentInfo.addInitialHandlerChainWrapper(new HandlerWrapper() {
@Override
public HttpHandler wrap(HttpHandler handler) {
return createAccessLogHandler(handler, accessLogReceiver);
}
});
} }
catch (IOException ex) { catch (IOException ex) {
throw new IllegalStateException("Failed to create AccessLogHandler", ex); throw new IllegalStateException("Failed to create AccessLogHandler", ex);
} }
} }
private AccessLogHandler createAccessLogHandler(HttpHandler handler,
AccessLogReceiver accessLogReceiver) {
createAccessLogDirectoryIfNecessary();
String formatString = (this.accessLogPattern != null) ? this.accessLogPattern
: "common";
return new AccessLogHandler(handler, accessLogReceiver, formatString,
Undertow.class.getClassLoader());
}
private void createAccessLogDirectoryIfNecessary() { private void createAccessLogDirectoryIfNecessary() {
Assert.state(this.accessLogDirectory != null, "Access log directory is not set"); Assert.state(this.accessLogDirectory != null, "Access log directory is not set");
if (!this.accessLogDirectory.isDirectory() && !this.accessLogDirectory.mkdirs()) { if (!this.accessLogDirectory.isDirectory() && !this.accessLogDirectory.mkdirs()) {
...@@ -790,4 +801,33 @@ public class UndertowEmbeddedServletContainerFactory ...@@ -790,4 +801,33 @@ public class UndertowEmbeddedServletContainerFactory
} }
private static class AccessLogShutdownListener implements ServletContextListener {
private final XnioWorker worker;
private final DefaultAccessLogReceiver accessLogReceiver;
AccessLogShutdownListener(XnioWorker worker,
DefaultAccessLogReceiver accessLogReceiver) {
this.worker = worker;
this.accessLogReceiver = accessLogReceiver;
}
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
try {
this.accessLogReceiver.close();
this.worker.shutdown();
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
}
} }
...@@ -37,6 +37,7 @@ import io.undertow.servlet.api.DeploymentInfo; ...@@ -37,6 +37,7 @@ import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.DeploymentManager; import io.undertow.servlet.api.DeploymentManager;
import io.undertow.servlet.api.ServletContainer; import io.undertow.servlet.api.ServletContainer;
import org.apache.jasper.servlet.JspServlet; import org.apache.jasper.servlet.JspServlet;
import org.junit.AfterClass;
import org.junit.Test; import org.junit.Test;
import org.mockito.InOrder; import org.mockito.InOrder;
...@@ -73,6 +74,11 @@ public class UndertowEmbeddedServletContainerFactoryTests ...@@ -73,6 +74,11 @@ public class UndertowEmbeddedServletContainerFactoryTests
return new UndertowEmbeddedServletContainerFactory(0); return new UndertowEmbeddedServletContainerFactory(0);
} }
@AfterClass
public static void afterClass() {
}
@Test @Test
public void errorPage404() throws Exception { public void errorPage404() throws Exception {
AbstractEmbeddedServletContainerFactory factory = getFactory(); AbstractEmbeddedServletContainerFactory factory = getFactory();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment