Spring Boot jetty/tomcat embedded access log configuration
For embedded Jetty you can also write this as part of your Spring Boot configuration:
@Bean
public EmbeddedServletContainerFactory jettyConfigBean() {
JettyEmbeddedServletContainerFactory jef = new JettyEmbeddedServletContainerFactory();
jef.addServerCustomizers(new JettyServerCustomizer() {
public void customize(Server server) {
HandlerCollection handlers = new HandlerCollection();
for (Handler handler : server.getHandlers()) {
handlers.addHandler(handler);
}
RequestLogHandler reqLogs = new RequestLogHandler();
NCSARequestLog reqLogImpl = new NCSARequestLog("./logs/access-yyyy_mm_dd.log");
reqLogImpl.setRetainDays(30);
reqLogImpl.setAppend(true);
reqLogImpl.setExtended(false);
reqLogImpl.setLogTimeZone("GMT");
reqLogs.setRequestLog(reqLogImpl);
handlers.addHandler(reqLogs);
server.setHandler(handlers);
// For Jetty 9.3+, use the following
//RequestLogHandler reqLogs = new RequestLogHandler();
//reqLogs.setServer(server);
//RequestLogImpl rli = new RequestLogImpl();
//rli.setResource("/logback-access.xml");
//rli.setQuiet(false);
//rli.start();
//reqLogs.setRequestLog(rli);
//handlers.addHandler(reqLogs);
//server.setHandler(handlers);
}
});
return jef;
}
You would have to include the relevant feature in your server container. E.g. for Tomcat add a LogbackValve
in an EmbeddedServletContainerCustomizer
bean. The TomcatEmbeddedServletContainerFactory
has a addContextValves
method for this purpose.
After many hours of trying to get a solution to work with SpringBoot 1.4 + Jetty + Logback-access I have finally found an answer to my woes.
Jetty's API interface changed in v9.3 and Logback-access no longer works.
http://shibboleth.1660669.n2.nabble.com/Jetty-9-3-access-logging-recommended-configuration-td7620755.html
There has been a pull request in the Logback project to get it to work again.
https://github.com/qos-ch/logback/pull/269
There a couple of solutions which are mentioned in the above pull request.
Option 1.
Use the org.eclipse.jetty.server.Slf4jRequestLog implementation to route the logging configuration back to classic Logback.
JettyConfiguration @Bean
RequestLogHandler requestLogsHandler = new RequestLogHandler();
requestLogsHandler.setServer(server);
Slf4jRequestLog log = new Slf4jRequestLog();
log.setLoggerName("com.example.accesslog");
requestLogsHandler.setRequestLog(log);
handlers.addHandler(requestLogsHandler);
server.setHandler(handlers);
logback.xml
<appender name="FILE-ACCESS" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/main.log</file>
<encoder>
<!-- You'll have to work this out -->
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/main.%d{yyyy-MM-dd}-%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>20MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>14</maxHistory>
</rollingPolicy>
</appender>
<logger name="com.example.accesslog">
<appender-ref ref="FILE-ACCESS" />
</logger>
This works but you lose all the access log specific parameters in the custom PatternLayout available with Logback-access. You probably need to roll your own pattern classes.
Thought this might work but it didn't (or I didn't do it properly).
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.access.PatternLayout">
<pattern>%h %l %u [%t] "%r" %s %b "%i{Referer}" "%i{User-Agent}"</pattern>
</layout>
</encoder>
Option 2
Also alluded to in the pull request above is a fix of the issue which can be used until it gets sorted.
Create a class that adds the missing interface and use that instead of RequestLogImpl.
New class
package com.example.ch.qos.logback.access.jetty;
import ch.qos.logback.access.jetty.RequestLogImpl;
import org.eclipse.jetty.util.component.LifeCycle;
public class LogbackAccessRequestLogImplFix1052 extends RequestLogImpl implements LifeCycle {
}
Jetty Configuration @Bean
RequestLogHandler requestLogs = new RequestLogHandler();
requestLogs.setServer(server);
LogbackAccessRequestLogImplFix1052 rli = new LogbackAccessRequestLogImplFix1052();
rli.setResource("/logback-access.xml");
rli.setQuiet(false);
requestLogs.setRequestLog(rli);
handlers.addHandler(requestLogs);
server.setHandler(handlers);
I tried both and ended up going with option 2 for now as I have spent tooooooooo long on this already. I would prefer option 1 though so I can keep all my logging config in the same file.
Good luck.