Commit 90e43737 authored by Marcos Barbero's avatar Marcos Barbero Committed by Andy Wilkinson

Add support for configuring Undertow's access log via the environment

This commit adds support for configuring Undertow's access log via the
environment using the following properties:

server.undertow.access-log-enabled
server.undertow.access-log-pattern
server.undertow.access-log-dir

See gh-3014
parent 3eb5c348
......@@ -56,6 +56,7 @@ import org.springframework.util.StringUtils;
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Ivan Sopov
* @author Marcos Barbero
*/
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = false)
public class ServerProperties implements EmbeddedServletContainerCustomizer, Ordered {
......@@ -578,6 +579,21 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
private Boolean directBuffers;
/**
* Format pattern for access logs.
*/
private String accessLogPattern;
/**
* Enable access log.
*/
private boolean accessLogEnabled = false;
/**
* Undertow access log directory. If not specified a temporary directory will be used.
*/
private File accessLogDir;
public Integer getBufferSize() {
return this.bufferSize;
}
......@@ -618,12 +634,39 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
this.directBuffers = directBuffers;
}
public String getAccessLogPattern() {
return accessLogPattern;
}
public void setAccessLogPattern(String accessLogPattern) {
this.accessLogPattern = accessLogPattern;
}
public boolean isAccessLogEnabled() {
return accessLogEnabled;
}
public void setAccessLogEnabled(boolean accessLogEnabled) {
this.accessLogEnabled = accessLogEnabled;
}
public File getAccessLogDir() {
return accessLogDir;
}
public void setAccessLogDir(File accessLogDir) {
this.accessLogDir = accessLogDir;
}
void customizeUndertow(UndertowEmbeddedServletContainerFactory factory) {
factory.setBufferSize(this.bufferSize);
factory.setBuffersPerRegion(this.buffersPerRegion);
factory.setIoThreads(this.ioThreads);
factory.setWorkerThreads(this.workerThreads);
factory.setDirectBuffers(this.directBuffers);
factory.setAccessLogDirectory(this.accessLogDir);
factory.setAccessLogPattern(this.accessLogPattern);
factory.setAccessLogEnabled(this.accessLogEnabled);
}
}
......
server.undertow.access-log-enabled=true
server.undertow.access-log-pattern=combined
\ No newline at end of file
......@@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory;
*
* @author Phillip Webb
* @author Dave Syer
* @author Marcos Barbero
*/
public abstract class AbstractEmbeddedServletContainerFactory extends
AbstractConfigurableEmbeddedServletContainer implements
......@@ -78,6 +79,25 @@ public abstract class AbstractEmbeddedServletContainerFactory extends
return file;
}
/**
* Returns the absolute temp dir for given web server.
* @param prefix webserver name
* @return The temp dir for given web server.
*/
protected File createTempDir(String prefix) {
try {
File tempFolder = File.createTempFile(prefix + ".", "." + getPort());
tempFolder.delete();
tempFolder.mkdir();
tempFolder.deleteOnExit();
return tempFolder;
}
catch (IOException ex) {
throw new EmbeddedServletContainerException(
String.format("Unable to create %s tempdir", prefix), ex);
}
}
private File getExplodedWarFileDocumentRoot() {
File file = getCodeSourceArchive();
if (this.logger.isDebugEnabled()) {
......
......@@ -79,6 +79,7 @@ import org.springframework.util.StringUtils;
* @author Brock Mills
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Marcos Barbero
* @see #setPort(int)
* @see #setContextLifecycleListeners(Collection)
* @see TomcatEmbeddedServletContainer
......@@ -382,20 +383,6 @@ public class TomcatEmbeddedServletContainerFactory extends
return new TomcatEmbeddedServletContainer(tomcat, getPort() >= 0);
}
private File createTempDir(String prefix) {
try {
File tempFolder = File.createTempFile(prefix + ".", "." + getPort());
tempFolder.delete();
tempFolder.mkdir();
tempFolder.deleteOnExit();
return tempFolder;
}
catch (IOException ex) {
throw new EmbeddedServletContainerException(
"Unable to create Tomcat tempdir", ex);
}
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
......
......@@ -19,6 +19,10 @@ package org.springframework.boot.context.embedded.undertow;
import io.undertow.Undertow;
import io.undertow.Undertow.Builder;
import io.undertow.UndertowMessages;
import io.undertow.server.HandlerWrapper;
import io.undertow.server.HttpHandler;
import io.undertow.server.handlers.accesslog.AccessLogHandler;
import io.undertow.server.handlers.accesslog.DefaultAccessLogReceiver;
import io.undertow.server.handlers.resource.ClassPathResourceManager;
import io.undertow.server.handlers.resource.FileResourceManager;
import io.undertow.server.handlers.resource.Resource;
......@@ -69,8 +73,11 @@ import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.xnio.OptionMap;
import org.xnio.Options;
import org.xnio.SslClientAuthMode;
import org.xnio.XnioWorker;
import org.xnio.Xnio;
/**
* {@link EmbeddedServletContainerFactory} that can be used to create
......@@ -81,6 +88,7 @@ import org.xnio.SslClientAuthMode;
*
* @author Ivan Sopov
* @author Andy Wilkinson
* @author Marcos Barbero
* @since 1.2.0
* @see UndertowEmbeddedServletContainer
*/
......@@ -105,6 +113,12 @@ public class UndertowEmbeddedServletContainerFactory extends
private Boolean directBuffers;
private File accessLogDirectory;
private String accessLogPattern;
private boolean accessLogEnabled = false;
/**
* Create a new {@link UndertowEmbeddedServletContainerFactory} instance.
*/
......@@ -337,6 +351,9 @@ public class UndertowEmbeddedServletContainerFactory extends
for (UndertowDeploymentInfoCustomizer customizer : this.deploymentInfoCustomizers) {
customizer.customize(deployment);
}
if (isAccessLogEnabled()) {
configureAccessLog(deployment);
}
DeploymentManager manager = Servlets.defaultContainer().addDeployment(deployment);
manager.deploy();
SessionManager sessionManager = manager.getDeployment().getSessionManager();
......@@ -345,6 +362,51 @@ public class UndertowEmbeddedServletContainerFactory extends
return manager;
}
private void configureAccessLog(DeploymentInfo deploymentInfo) {
deploymentInfo.addInitialHandlerChainWrapper(new HandlerWrapper() {
@Override
public HttpHandler wrap(HttpHandler handler) {
try {
String formatString = (accessLogPattern != null) ? accessLogPattern
: "common";
DefaultAccessLogReceiver accessLogReceiver = new DefaultAccessLogReceiver(
createWorker(), getLogsDir(), "access_log");
return new AccessLogHandler(handler, accessLogReceiver, formatString,
Undertow.class.getClassLoader());
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
});
}
private XnioWorker createWorker() throws IOException {
Xnio xnio = Xnio.getInstance(Undertow.class.getClassLoader());
OptionMap.Builder builder = OptionMap.builder();
if(this.ioThreads != null && this.ioThreads > 0) {
builder.set(Options.WORKER_IO_THREADS, ioThreads);
}
if(this.workerThreads != null && this.workerThreads > 0) {
builder.set(Options.WORKER_TASK_CORE_THREADS, workerThreads);
builder.set(Options.WORKER_TASK_MAX_THREADS, workerThreads);
}
return xnio.createWorker(builder.getMap());
}
private File getLogsDir() {
File logsDir;
if (accessLogDirectory != null) {
logsDir = accessLogDirectory;
if (!logsDir.isDirectory() && !logsDir.mkdirs()) {
throw new IllegalStateException("Failed to create logs dir '" + logsDir + "'");
}
} else {
logsDir = createTempDir("undertow");
}
return logsDir;
}
private void registerServletContainerInitializerToDriveServletContextInitializers(
DeploymentInfo deployment, ServletContextInitializer... initializers) {
ServletContextInitializer[] mergedInitializers = mergeInitializers(initializers);
......@@ -442,6 +504,22 @@ public class UndertowEmbeddedServletContainerFactory extends
this.directBuffers = directBuffers;
}
public void setAccessLogDirectory(File accessLogDirectory) {
this.accessLogDirectory = accessLogDirectory;
}
public void setAccessLogPattern(String accessLogPattern) {
this.accessLogPattern = accessLogPattern;
}
public void setAccessLogEnabled(boolean accessLogEnabled) {
this.accessLogEnabled = accessLogEnabled;
}
public boolean isAccessLogEnabled() {
return accessLogEnabled;
}
/**
* Undertow {@link ResourceManager} for JAR resources.
*/
......
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