我正在使用Spring Boot 1.1.5.RELEASE构建一个Web应用程序,并且我已经按照in the related Spring Boot's documentation所述配置了一个嵌入式Jetty。
我想记录所有传入的HTTP请求,我能想到的唯一解决方案(在Spring Boot的文档中阅读"how to configure Jetty"之后)是介绍EmbeddedServletContainerCustomizer:
package com.acme.rest;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.jetty.JettyServerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* blah blah
*
* @author Dimi
*/
@Component
public class EmbededJettyConfig implements EmbeddedServletContainerCustomizer {
/*
* (non-Javadoc)
*
* @see org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer # customize
*/
@Override
public void customize(final ConfigurableEmbeddedServletContainer container) {
// checks whether the container is Jetty
if (container instanceof JettyEmbeddedServletContainerFactory) {
((JettyEmbeddedServletContainerFactory) container)
.addServerCustomizers(jettyServerCustomizer());
}
}
@Bean
public JettyServerCustomizer jettyServerCustomizer() {
return new JettyServerCustomizer() {
/*
* (non-Javadoc)
*
* @see org.springframework.boot.context.embedded.jetty.JettyServerCustomizer #
* customize
*/
@Override
public void customize(final Server server) {
HandlerCollection handlers = new HandlerCollection();
RequestLogHandler requestLogHandler = new RequestLogHandler();
handlers.setHandlers(new Handler[] {new DefaultHandler(), requestLogHandler});
server.setHandler(handlers);
NCSARequestLog requestLog = new NCSARequestLog("logs/requests.log");
requestLog.setExtended(false);
requestLogHandler.setRequestLog(requestLog);
}
};
}
}
应用程序现在无法开始抛出异常:
java.lang.IllegalArgumentException:需要ServletContext 配置默认servlet处理
简而言之:在Spring Boot中配置嵌入式Jetty日志记录的正确方法是什么?
答案 0 :(得分:4)
Jetty 9.3.8在服务器上有一个新方法setRequestLog
。
@Component
public class EnableRequestLog implements EmbeddedServletContainerCustomizer {
private static final JettyServerCustomizer USE_SLF4J_REQUEST_LOG =
server -> server.setRequestLog(new Slf4jRequestLog());
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof JettyEmbeddedServletContainerFactory) {
((JettyEmbeddedServletContainerFactory) container)
.addServerCustomizers(USE_SLF4J_REQUEST_LOG);
} else {
throw new IllegalArgumentException(
"Expected a Jetty container factory but encountered " + container.getClass());
}
}
}
您可以实现特定的RequestLog
,而不是Jetty的Slf4jRequestLog。见http://www.eclipse.org/jetty/documentation/current/configuring-jetty-request-logs.html
答案 1 :(得分:1)
巧合的是,Jetty一直在分析RequestLogHandler
行为并最近使用,着眼于记录错误条件,异常和异步。
最近爆出的错误:
让我们假设我们有RequestLogHandler
这样的设置......
File logDir = new File(System.getProperty("log.dir"));
NCSARequestLog ncsaLog = new NCSARequestLog();
ncsaLog.setFilename(new File(logDir, "yyyy_MM_dd.request.log").getAbsolutePath());
ncsaLog.setFilenameDateFormat("yyyy_MM_dd");
ncsaLog.setExtended(true);
ncsaLog.setAppend(true);
ncsaLog.setLogTimeZone("GMT");
ncsaLog.setRetainDays(90);
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(ncsaLog);
在服务器中使用处理程序设置的旧方法是以下列方式。
HandlerCollection handlers = new HandlerCollection();
handlers.addHandler(myHandlers);
handlers.addHandler(new DefaultHandler());
handlers.addHandler(requestLogHandler());
server.setHandler(handlers);
处理程序链看起来像这样:
事实证明,将RequestLogHandler
连接到您的处理程序链是一种糟糕的方法,因为捕获并记录的错误条件很少。
建议将RequestLogHandler
包裹在应记录的处理程序链中。
HandlerCollection handlers = new HandlerCollection();
handlers.addHandler(myHandlers);
handlers.addHandler(new DefaultHandler());
requestLogHandler.setHandler(handlers);
server.setHandler(requestLogHandler);
处理程序链看起来像这样:
这是连接RequestLogHandler
的正确方法。
这甚至可以帮助过滤人员不希望记录的处理程序(例如重写/重定向操作)的日志记录事件。
只需将您不想登录的处理程序放在RequestLogHandler
这样的结构:
根据您的RewriteHandler规则(如果您是否重定向,以及是否终止),将不会发生日志记录事件。
答案 2 :(得分:1)
稍微迟了一点,但我遇到了同样的问题,解决方案是将已经由boot创建的ServletHandler包装在RequestLogHandler中,如下所示:
@Component
public class EmbededJettyConfig implements EmbeddedServletContainerCustomizer {
/*
* (non-Javadoc)
*
* @see org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer # customize
*/
@Override
public void customize(final ConfigurableEmbeddedServletContainer container) {
// checks whether the container is Jetty
if (container instanceof JettyEmbeddedServletContainerFactory) {
((JettyEmbeddedServletContainerFactory) container)
.addServerCustomizers(jettyServerCustomizer());
}
}
@Bean
public JettyServerCustomizer jettyServerCustomizer() {
return new JettyServerCustomizer() {
/*
* (non-Javadoc)
*
* @see org.springframework.boot.context.embedded.jetty.JettyServerCustomizer #
* customize
*/
@Override
public void customize(final Server server) {
NCSARequestLog requestLog = new NCSARequestLog("logs/requests.log");
requestLog.setExtended(false);
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(requestLog);
requestLogHandler.setHandler(server.getHandler());
server.setHandler(requestLogHandler);
}
};
}
答案 3 :(得分:-1)
这不适用于Spring Boot 1.1.9版,因为JettyEmbeddedServletContainer只处理JettyEmbeddedWebAppContext(处理程序)或HandlerWrapper。我认为没有办法在Spring Boot中为嵌入式Jetty设置多个处理程序。
来自org.springframework.boot.context.embedded.jettyJettyEmbeddedServletContainer的代码片段。
@Override
public void start() throws EmbeddedServletContainerException {
this.server.setConnectors(this.connectors);
if (!this.autoStart) {
return;
}
try {
this.server.start();
for (Handler handler : this.server.getHandlers()) {
handleDeferredInitialize(handler);
}
Connector[] connectors = this.server.getConnectors();
for (Connector connector : connectors) {
connector.start();
this.logger.info("Jetty started on port: " + getLocalPort(connector));
}
}
catch (Exception ex) {
throw new EmbeddedServletContainerException(
"Unable to start embedded Jetty servlet container", ex);
}
}
private void handleDeferredInitialize(Handler handler) throws Exception {
if (handler instanceof JettyEmbeddedWebAppContext) {
((JettyEmbeddedWebAppContext) handler).deferredInitialize();
}
else if (handler instanceof HandlerWrapper) {
handleDeferredInitialize(((HandlerWrapper) handler).getHandler());
}
}