自 Jetty 9.x 以来,RequestLog 整体发生了一些重要变化
RequestLog 实现现在已添加到Server,不要使用老式的RequestLogHandler。
// Modern version (for all system loads and speeds)
Slf4jRequestLogWriter slfjRequestLogWriter = new Slf4jRequestLogWriter();
slfjRequestLogWriter.setLoggerName("com.company.request.log");
String format = "%{client}a - %u %t '%r' %s %O '%{Referer}i' '%{User-Agent}i' '%C'";
CustomRequestLog customRequestLog = new CustomRequestLog(slfjRequestLogWriter, format);
server.setRequestLog(customRequestLog);
// Old school version (not for busy systems)
Path outputPattern = logsDir.resolve("yyyy_mm_dd.request.log");
AsyncRequestLogWriter logWriter = new AsyncRequestLogWriter(outputPattern.toString());
logWriter.setFilenameDateFormat("yyyy_MM_dd");
logWriter.setRetainDays(90);
logWriter.setTimeZone("GMT");
String format = "%{client}a - %u %t '%r' %s %O '%{Referer}i' '%{User-Agent}i' '%C'";
CustomRequestLog requestLog = new CustomRequestLog(logWriter, format);
server.setRequestLog(requestLog);
虽然RequestLogHandler 仍然存在,但它有一些基本缺陷,即它不会记录在解析步骤期间失败的请求,或在合规性验证步骤期间失败的请求,或在 ssl/tls 验证步骤期间失败的请求,或不属于已知上下文的请求,或在响应生成期间失败的交换,或通过错误处理层返回应用程序但在应用程序层失败的交换等。如您所见,有很多边缘情况RequestLogHandler 无法处理,所以创建了基础Server.setRequestLog(RequestLog),使用它。
Request 和 Response 的内部更改已在每个组件“提交”时保持这些组件的状态,因此您必须使用 Request 和 Response 中的这些新方法来在网络层实际处理这些对象时,获取有关这些对象状态的准确信息。由于 when 在 http 交换和生命周期期间发生日志记录,使用原始方法很容易导致错误/不准确的数据。
RequestLog Jetty 的实现由两部分组成。
RequestLog 本身是一个接受Request 和Response 并将信息格式化为日志行字符串的组件。
RequestLog 使用RequestLog.Writer 组件将原始字符串写入任何必要的内容。
-
Slf4jRequestLogWriter(默认实现,推荐)- 将字符串写入名为 logger 的 slf4j。这是设置唯一日志文件、滚动行为(按大小、日期、任意持续时间或其他触发器)、旧日志归档(带压缩)、警报、支持扩展访问日志分析工具等的最佳选择.
-
RequestLogWriter(老派,很多陷阱)- 同步写入任意任意OutputStream(您可以在此处使用 Jetty 的老派RolloverFileOutputStream)。这将在收到每个条目后写入,如果您的网络事件超过磁盘 I/O 可以处理的数量(一个令人惊讶的常见情况),请切换到使用异步版本突发写入。
-
AsyncRequestLogWriter - RequestLogWriter 的异步版本,如果您的磁盘 I/O 仍然无法处理更多的网络事件,请切换到 Slf4jRequestLogWriter 并使用各种 slf4j 实现的高级异步日志附加,这比比 Jetty 本身在 AsyncRequestLogWriter 中使用的简单 java.io 行为。
自定义请求日志的最常见形式是更改记录的内容,而不是自定义输出格式(已由CustomRequestLog 本身处理)。
一个例子是只记录错误情况,而不记录其余情况。
请注意,这显示了上述“已提交”状态信息的示例。
package jetty;
import org.eclipse.jetty.server.CustomRequestLog;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
public class ErrorOnlyRequestLog extends CustomRequestLog
{
public ErrorOnlyRequestLog(Writer writer, String formatString)
{
super(writer, formatString);
}
public ErrorOnlyRequestLog(String file)
{
super(file);
}
public ErrorOnlyRequestLog(String file, String format)
{
super(file, format);
}
@Override
public void log(Request request, Response response)
{
// Get the response status actually sent (as you cannot rely on
// the Response.getStatus() at this point in time, which can change
// due to a number of factors, including error handling, dispatch
// completion, recycling, etc)
int committedStatus = response.getCommittedMetaData().getStatus();
// only interested in error cases - bad request & server errors
if ((committedStatus >= 500) || (committedStatus == 400))
{
super.log(request, response);
}
else
{
System.err.println("### Ignored request (response.committed.status=" + committedStatus + "): " + request);
}
}
}