本文介紹了如何覆蓋Jetty 11.0.6中的請求日志記錄機制的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我正在將jetty 9更新為jetty11,我看到org.eclipse.jetty.server.AsyncNCSARequestLog已過時,為此引入了另外兩個類-org.eclipse.jetty.server.CustomRequestLog和org.eclipse.jetty.server.AsyncRequestLogWriter.
但問題是,我過去習慣于擴展AsyncNCSARequestLog類并重寫日志和寫入方法(有關詳細信息,請參閱下面的代碼),但找不到在Jetty11中執行此操作的方法。
public class JettyRequestLogger extends AsyncNCSARequestLog
{
private Request request;
@Override
public void log(Request request, Response response)
{
this.request = request;
super.log(request, response);
}
@Override
public void write(String logStr) throws IOException
{
logStr = setCustomAttributesToLog(logStr);
super.write(logStr);
}
private String setCustomAttributesToLog(String logStr)
{
// logic here
}
}
更新:
我的用例是在打印Jetty日志時添加用戶ID、用戶名和自定義屬性等自定義屬性
推薦答案
自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
中的新方法來獲取有關這些對象在網絡層實際處理時的狀態的準確信息。由于當日志記錄發生在http交換和生命周期期間,使用原始方法很容易導致數據錯誤/不準確。
RequestLog
Jetty發布的實現由兩部分組成。
RequestLog
本身是接受Request
和Response
并將信息格式化為日志行字符串的組件。
RequestLog.Writer
組件由RequestLog
用于將原始字符串寫入任何需要的內容。
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);
}
}
}
這篇關于如何覆蓋Jetty 11.0.6中的請求日志記錄機制的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,