Merge pull request #8819 from olamy:feature/jetty_accesslog
* pr/8819: Add support for configuring Jetty's request log via the environment Add support for configuring Jetty's request log via the environment
This commit is contained in:
commit
b426bba169
|
@ -23,8 +23,10 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
|
||||
|
@ -48,6 +50,7 @@ import org.springframework.util.StringUtils;
|
|||
* @author Venil Noronha
|
||||
* @author Aurélien Leboulanger
|
||||
* @author Brian Clozel
|
||||
* @author Olivier Lamy
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
|
||||
public class ServerProperties {
|
||||
|
@ -885,6 +888,11 @@ public class ServerProperties {
|
|||
*/
|
||||
public static class Jetty {
|
||||
|
||||
/**
|
||||
* Access log configuration.
|
||||
*/
|
||||
private final Accesslog accesslog = new Accesslog();
|
||||
|
||||
/**
|
||||
* Maximum size in bytes of the HTTP post or put content.
|
||||
*/
|
||||
|
@ -900,6 +908,10 @@ public class ServerProperties {
|
|||
*/
|
||||
private Integer selectors;
|
||||
|
||||
public Accesslog getAccesslog() {
|
||||
return this.accesslog;
|
||||
}
|
||||
|
||||
public int getMaxHttpPostSize() {
|
||||
return this.maxHttpPostSize;
|
||||
}
|
||||
|
@ -924,6 +936,168 @@ public class ServerProperties {
|
|||
this.selectors = selectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Jetty access log properties.
|
||||
*/
|
||||
public static class Accesslog {
|
||||
|
||||
/**
|
||||
* Enable access log.
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* Log filename. If not specified, logs will be redirected to "System.err".
|
||||
*/
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* Date format to place in log file name.
|
||||
*/
|
||||
private String fileDateFormat;
|
||||
|
||||
/**
|
||||
* Number of days before rotated log files are deleted.
|
||||
*/
|
||||
private int retentionPeriod = 31; // no days
|
||||
|
||||
/**
|
||||
* Append to log.
|
||||
*/
|
||||
private boolean append;
|
||||
|
||||
/**
|
||||
* Enable extended NCSA format.
|
||||
*/
|
||||
private boolean extendedFormat;
|
||||
|
||||
/**
|
||||
* Timestamp format of the request log.
|
||||
*/
|
||||
private String dateFormat = "dd/MMM/yyyy:HH:mm:ss Z";
|
||||
|
||||
/**
|
||||
* Locale of the request log.
|
||||
*/
|
||||
private Locale locale;
|
||||
|
||||
/**
|
||||
* Timezone of the request log.
|
||||
*/
|
||||
private TimeZone timeZone = TimeZone.getTimeZone("GMT");
|
||||
|
||||
/**
|
||||
* Enable logging of the request cookies.
|
||||
*/
|
||||
private boolean logCookies;
|
||||
|
||||
/**
|
||||
* Enable logging of the request hostname.
|
||||
*/
|
||||
private boolean logServer;
|
||||
|
||||
/**
|
||||
* Enable logging of request processing time.
|
||||
*/
|
||||
private boolean logLatency;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return this.filename;
|
||||
}
|
||||
|
||||
public void setFilename(String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public String getFileDateFormat() {
|
||||
return this.fileDateFormat;
|
||||
}
|
||||
|
||||
public void setFileDateFormat(String fileDateFormat) {
|
||||
this.fileDateFormat = fileDateFormat;
|
||||
}
|
||||
|
||||
public int getRetentionPeriod() {
|
||||
return this.retentionPeriod;
|
||||
}
|
||||
|
||||
public void setRetentionPeriod(int retentionPeriod) {
|
||||
this.retentionPeriod = retentionPeriod;
|
||||
}
|
||||
|
||||
public boolean isAppend() {
|
||||
return this.append;
|
||||
}
|
||||
|
||||
public void setAppend(boolean append) {
|
||||
this.append = append;
|
||||
}
|
||||
|
||||
public boolean isExtendedFormat() {
|
||||
return this.extendedFormat;
|
||||
}
|
||||
|
||||
public void setExtendedFormat(boolean extendedFormat) {
|
||||
this.extendedFormat = extendedFormat;
|
||||
}
|
||||
|
||||
public String getDateFormat() {
|
||||
return this.dateFormat;
|
||||
}
|
||||
|
||||
public void setDateFormat(String dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return this.locale;
|
||||
}
|
||||
|
||||
public void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public TimeZone getTimeZone() {
|
||||
return this.timeZone;
|
||||
}
|
||||
|
||||
public void setTimeZone(TimeZone timeZone) {
|
||||
this.timeZone = timeZone;
|
||||
}
|
||||
|
||||
public boolean isLogCookies() {
|
||||
return this.logCookies;
|
||||
}
|
||||
|
||||
public void setLogCookies(boolean logCookies) {
|
||||
this.logCookies = logCookies;
|
||||
}
|
||||
|
||||
public boolean isLogServer() {
|
||||
return this.logServer;
|
||||
}
|
||||
|
||||
public void setLogServer(boolean logServer) {
|
||||
this.logServer = logServer;
|
||||
}
|
||||
|
||||
public boolean isLogLatency() {
|
||||
return this.logLatency;
|
||||
}
|
||||
|
||||
public void setLogLatency(boolean logLatency) {
|
||||
this.logLatency = logLatency;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.eclipse.jetty.server.AbstractConnector;
|
|||
import org.eclipse.jetty.server.ConnectionFactory;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.NCSARequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
|
@ -66,6 +67,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Brian Clozel
|
||||
* @author Stephane Nicoll
|
||||
* @author Olivier Lamy
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DefaultServletWebServerFactoryCustomizer
|
||||
|
@ -541,6 +543,9 @@ public class DefaultServletWebServerFactoryCustomizer
|
|||
customizeConnectionTimeout(factory,
|
||||
serverProperties.getConnectionTimeout());
|
||||
}
|
||||
if (jettyProperties.getAccesslog().isEnabled()) {
|
||||
customizeAccesslog(factory, jettyProperties.getAccesslog());
|
||||
}
|
||||
}
|
||||
|
||||
private static void customizeConnectionTimeout(
|
||||
|
@ -637,6 +642,35 @@ public class DefaultServletWebServerFactoryCustomizer
|
|||
|
||||
});
|
||||
}
|
||||
|
||||
private static void customizeAccesslog(JettyServletWebServerFactory factory,
|
||||
final ServerProperties.Jetty.Accesslog accesslog) {
|
||||
factory.addServerCustomizers(server -> {
|
||||
NCSARequestLog requestLog = new NCSARequestLog();
|
||||
if (accesslog.getFilename() != null) {
|
||||
requestLog.setFilename(accesslog.getFilename());
|
||||
}
|
||||
if (accesslog.getFileDateFormat() != null) {
|
||||
requestLog.setFilenameDateFormat(accesslog.getFileDateFormat());
|
||||
}
|
||||
requestLog.setRetainDays(accesslog.getRetentionPeriod());
|
||||
requestLog.setAppend(accesslog.isAppend());
|
||||
requestLog.setExtended(accesslog.isExtendedFormat());
|
||||
if (accesslog.getDateFormat() != null) {
|
||||
requestLog.setLogDateFormat(accesslog.getDateFormat());
|
||||
}
|
||||
if (accesslog.getLocale() != null) {
|
||||
requestLog.setLogLocale(accesslog.getLocale());
|
||||
}
|
||||
if (accesslog.getTimeZone() != null) {
|
||||
requestLog.setLogTimeZone(accesslog.getTimeZone().getID());
|
||||
}
|
||||
requestLog.setLogCookies(accesslog.isLogCookies());
|
||||
requestLog.setLogServer(accesslog.isLogServer());
|
||||
requestLog.setLogLatency(accesslog.isLogLatency());
|
||||
server.setRequestLog(requestLog);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -184,6 +184,23 @@ public class ServerPropertiesTests {
|
|||
assertThat(this.properties.getJetty().getSelectors()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomizeJettyAccessLog() throws Exception {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("server.jetty.accesslog.enabled", "true");
|
||||
map.put("server.jetty.accesslog.filename", "foo.txt");
|
||||
map.put("server.jetty.accesslog.file-date-format", "yyyymmdd");
|
||||
map.put("server.jetty.accesslog.retention-period", "4");
|
||||
map.put("server.jetty.accesslog.append", "true");
|
||||
bindProperties(map);
|
||||
ServerProperties.Jetty jetty = this.properties.getJetty();
|
||||
assertThat(jetty.getAccesslog().isEnabled()).isEqualTo(true);
|
||||
assertThat(jetty.getAccesslog().getFilename()).isEqualTo("foo.txt");
|
||||
assertThat(jetty.getAccesslog().getFileDateFormat()).isEqualTo("yyyymmdd");
|
||||
assertThat(jetty.getAccesslog().getRetentionPeriod()).isEqualTo(4);
|
||||
assertThat(jetty.getAccesslog().isAppend()).isEqualTo(true);
|
||||
}
|
||||
|
||||
private void bindProperties(Map<String, String> map) {
|
||||
new RelaxedDataBinder(this.properties, "server")
|
||||
.bind(new MutablePropertyValues(map));
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.io.File;
|
|||
import java.net.URL;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
@ -33,6 +34,8 @@ import org.apache.catalina.valves.AccessLogValve;
|
|||
import org.apache.catalina.valves.RemoteIpValve;
|
||||
import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
|
||||
import org.apache.coyote.AbstractProtocol;
|
||||
import org.eclipse.jetty.server.NCSARequestLog;
|
||||
import org.eclipse.jetty.server.RequestLog;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -45,6 +48,7 @@ import org.springframework.beans.MutablePropertyValues;
|
|||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.bind.RelaxedDataBinder;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.jetty.JettyWebServer;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
|
||||
|
@ -527,6 +531,72 @@ public class DefaultServletWebServerFactoryCustomizerTests {
|
|||
verify(factory).setSessionStoreDir(new File("myfolder"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jettyAccessLogCanBeEnabled() {
|
||||
JettyServletWebServerFactory factory = new JettyServletWebServerFactory(0);
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("server.jetty.accesslog.enabled", "true");
|
||||
bindProperties(map);
|
||||
this.customizer.customize(factory);
|
||||
JettyWebServer webServer = (JettyWebServer) factory.getWebServer();
|
||||
try {
|
||||
NCSARequestLog requestLog = getNCSARequestLog(webServer);
|
||||
assertThat(requestLog.getFilename()).isNull();
|
||||
assertThat(requestLog.isAppend()).isFalse();
|
||||
assertThat(requestLog.isExtended()).isFalse();
|
||||
assertThat(requestLog.getLogCookies()).isFalse();
|
||||
assertThat(requestLog.getLogServer()).isFalse();
|
||||
assertThat(requestLog.getLogLatency()).isFalse();
|
||||
}
|
||||
finally {
|
||||
webServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jettyAccessLogCanBeCustomized() {
|
||||
JettyServletWebServerFactory factory = new JettyServletWebServerFactory(0);
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("server.jetty.accesslog.enabled", "true");
|
||||
map.put("server.jetty.accesslog.filename", "foo");
|
||||
map.put("server.jetty.accesslog.file-date-format", "yyyy-MM-dd");
|
||||
map.put("server.jetty.accesslog.retention-period", "42");
|
||||
map.put("server.jetty.accesslog.append", "true");
|
||||
map.put("server.jetty.accesslog.extended-format", "true");
|
||||
map.put("server.jetty.accesslog.date-format", "HH:mm:ss");
|
||||
map.put("server.jetty.accesslog.locale", "en_BE");
|
||||
map.put("server.jetty.accesslog.time-zone", "UTC");
|
||||
map.put("server.jetty.accesslog.log-cookies", "true");
|
||||
map.put("server.jetty.accesslog.log-server", "true");
|
||||
map.put("server.jetty.accesslog.log-latency", "true");
|
||||
bindProperties(map);
|
||||
this.customizer.customize(factory);
|
||||
JettyWebServer webServer = (JettyWebServer) factory.getWebServer();
|
||||
NCSARequestLog requestLog = getNCSARequestLog(webServer);
|
||||
try {
|
||||
assertThat(requestLog.getFilename()).isEqualTo("foo");
|
||||
assertThat(requestLog.getFilenameDateFormat()).isEqualTo("yyyy-MM-dd");
|
||||
assertThat(requestLog.getRetainDays()).isEqualTo(42);
|
||||
assertThat(requestLog.isAppend()).isTrue();
|
||||
assertThat(requestLog.isExtended()).isTrue();
|
||||
assertThat(requestLog.getLogDateFormat()).isEqualTo("HH:mm:ss");
|
||||
assertThat(requestLog.getLogLocale()).isEqualTo(new Locale("en", "BE"));
|
||||
assertThat(requestLog.getLogTimeZone()).isEqualTo("UTC");
|
||||
assertThat(requestLog.getLogCookies()).isTrue();
|
||||
assertThat(requestLog.getLogServer()).isTrue();
|
||||
assertThat(requestLog.getLogLatency()).isTrue();
|
||||
}
|
||||
finally {
|
||||
webServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private NCSARequestLog getNCSARequestLog(JettyWebServer webServer) {
|
||||
RequestLog requestLog = webServer.getServer().getRequestLog();
|
||||
assertThat(requestLog).isInstanceOf(NCSARequestLog.class);
|
||||
return (NCSARequestLog) requestLog;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipNullElementsForUndertow() throws Exception {
|
||||
UndertowServletWebServerFactory factory = mock(
|
||||
|
|
|
@ -157,6 +157,18 @@ content into your application; rather pick only the properties that you need.
|
|||
server.error.path=/error # Path of the error controller.
|
||||
server.error.whitelabel.enabled=true # Enable the default error page displayed in browsers in case of a server error.
|
||||
server.jetty.acceptors= # Number of acceptor threads to use.
|
||||
server.jetty.accesslog.append=false # Append to log.
|
||||
server.jetty.accesslog.date-format=dd/MMM/yyyy:HH:mm:ss Z # Timestamp format of the request log.
|
||||
server.jetty.accesslog.enabled=false # Enable access log.
|
||||
server.jetty.accesslog.extended-format=false # Enable extended NCSA format.
|
||||
server.jetty.accesslog.file-date-format= # Date format to place in log file name.
|
||||
server.jetty.accesslog.filename= # Log filename. If not specified, logs will be redirected to "System.err".
|
||||
server.jetty.accesslog.locale= # Locale of the request log.
|
||||
server.jetty.accesslog.log-cookies=false # Enable logging of the request cookies.
|
||||
server.jetty.accesslog.log-latency=false # Enable logging of request processing time.
|
||||
server.jetty.accesslog.log-server=false # Enable logging of the request hostname.
|
||||
server.jetty.accesslog.retention-period=31 # Number of days before rotated log files are deleted.
|
||||
server.jetty.accesslog.time-zone=GMT # Timezone of the request log.
|
||||
server.jetty.max-http-post-size=0 # Maximum size in bytes of the HTTP post or put content.
|
||||
server.jetty.selectors= # Number of selector threads to use.
|
||||
server.port=8080 # Server HTTP port.
|
||||
|
|
|
@ -636,7 +636,8 @@ sample project for an example.
|
|||
|
||||
[[howto-configure-accesslogs]]
|
||||
=== Configure Access Logging
|
||||
Access logs can be configured for Tomcat and Undertow via their respective namespaces.
|
||||
Access logs can be configured for Tomcat, Undertow and Jetty via their respective
|
||||
namespaces.
|
||||
|
||||
For instance, the following logs access on Tomcat with a
|
||||
https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html#Access_Logging[custom pattern].
|
||||
|
@ -664,6 +665,17 @@ Access logging for undertow can be configured in a similar fashion
|
|||
Logs are stored in a `logs` directory relative to the working directory of the
|
||||
application. This can be customized via `server.undertow.accesslog.directory`.
|
||||
|
||||
Finally, access logging for jetty can also be configured that way:
|
||||
|
||||
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
server.jetty.accesslog.enabled=true
|
||||
server.jetty.accesslog.filename=access-log
|
||||
----
|
||||
|
||||
By default, logs will be redirected to `System.err`. For more details, please refer to
|
||||
https://www.eclipse.org/jetty/documentation/9.3.x/configuring-jetty-request-logs.html[the documentation].
|
||||
|
||||
|
||||
|
||||
[[howto-use-behind-a-proxy-server]]
|
||||
|
|
Loading…
Reference in New Issue