使用 Java 日誌過濾器解析 HTTP 請求
javax.servlet.Filter一種實作和解析HTTP請求內容和輸出日誌的便捷方法。篩選介紹班級。
此日誌過濾器使用“java.util.logging.Logger”進行日誌輸出,您可以透過變更日誌等級來變更資訊輸出。
什麼是 javax.servlet.Filter?
在建構Web應用時,除了主要業務處理之外,還需要在主要業務處理前後進行常見的二次處理。
例如,客戶端認證、權限檢查、日誌記錄等。
在每個資源中對這種副處理進行編碼成為阻礙軟體可維護性的主要原因,導致應用程式難以維護。
透過實作 javax.servlet.Filter,您通常可以在請求傳遞到 servlet 類別之前執行此端處理。
另外,由於過濾器設定可以在web.xml中完成,因此您可以靈活地新增或刪除過濾器,而無需更改原始程式碼。
嘗試使用日誌過濾器
讓我們實際使用日誌過濾器來過濾 HTTP 請求並對其進行分析。
這次雄貓我們將使用從一開始就可用的範例應用程式。
您可以透過進行以下設定立即運行此過濾器。
日誌過濾器日誌過濾器日誌等級美好的日誌過濾器/*
*使用Struts框架時的url-pattern如下。
*。做
請檢查執行會話範例畫面的日誌輸出結果。
輸出日誌資訊和日誌級別
●日誌輸出內容
日誌資訊 | 日誌等級 |
---|---|
Cookie 資訊 | 美好的 |
HTTP頭訊息 | 美好的 |
HTTP其他資訊 | 美好的 |
HTTP請求參數 | 配置 |
請求範圍對象 | 配置 |
會話範圍的對象 | 配置 |
請求前後的記憶體使用情況 | 配置 |
螢幕轉換訊息 | 資訊 |
最好如下使用日誌等級。
- FINE:輸出最詳細的日誌。如果您想詳細分析 HTTP 請求,請設定此項。
- CONFIG... 輸出比較詳細的日誌。在開發期間將其保持在這個水平是一個好主意。
- INFO:僅輸出螢幕轉換訊息。
●如何更改日誌等級
您可以透過設定初始化參數logging.Level來變更日誌輸出等級。
例子:
日誌等級資訊
原始碼
導入 javax.servlet.Filter;
導入 javax.servlet.FilterChain;
導入 javax.servlet.FilterConfig;
導入 javax.servlet.ServletException;
導入 javax.servlet.ServletRequest;
導入 javax.servlet.ServletResponse;
導入javax.servlet.http.Cookie;
導入 javax.servlet.http.HttpServletRequest;
導入 javax.servlet.http.HttpServletResponse;
導入 javax.servlet.http.HttpSession;
/**
* 實作javax.servlet.Filter來分析HTTP請求內容並輸出日誌
* 過濾器類別。
*/
公共類別 LogFilter 實作 Filter {
私人靜態記錄器記錄器 =
Logger.getLogger(LogFilter.class.getName());
私有靜態最終字串 LINE_SEPA =
System.getProperty(“line.separator”);
私有靜態最終字串NEXT_PAGE =“LogFilter.NEXT_PAGE”;
/**
* 初始化該日誌過濾器。
* @參數映射
*/
公共無效初始化(FilterConfig映射){
String str = mapping.getInitParameter(“logging.Level”);
System.out.println(“設定日誌等級為“+str+”。”);
等級 level = null;
嘗試 {
級別 = Level.parse(str);
} catch (異常 e) {
e.printStackTrace();
級別 = 級別.INFO;
}
LogManager.getLogManager().reset();
處理程序 handler = new CustomConsoleHandler();
handler.setFormatter(new CustomFormatter());
handler.setLevel(級別);
logger.setLevel(級別);
logger.getParent().addHandler(處理程序);
}
/**
* 這是一個輸出日誌的過濾器。
* @param request 正在處理的HTTP請求
* @param response 正在產生 HTTP 回應
* @參數鏈
*/
公共無效 doFilter(ServletRequest _request, ServletResponse _response,
FilterChain 鏈)拋出 IOException、ServletException {
// --------------------“預處理”
HttpServletRequest 請求 = (HttpServletRequest)_request;
HttpServletResponse 回應 = (HttpServletResponse) _response;
如果(logger.isLoggable(Level.CONFIG)){
記錄器.config(
“============請求開始!!”
+“線程ID:”
+ Thread.currentThread().hashCode()
+ ” ========================================================”);
}
// 記憶體使用情況
字串actionMemory = null;
如果(logger.isLoggable(Level.CONFIG)){
動作記憶體 = getMemoryInfo(” ”
+ new Time(System.currentTimeMillis()) + ”Request[上一個]”);
}
如果 (logger.isLoggable(Level.FINE)) {
logger.fine(“Cookie 資訊” + getCookieInfo(request));
}
如果 (logger.isLoggable(Level.FINE)) {
logger.fine(“HTTP頭資訊” + getHeadersInfo(request));
}
如果 (logger.isLoggable(Level.FINE)) {
記錄器
.fine(“HTTP其他資訊” + getRequestOtherInfo(request));
}
如果(logger.isLoggable(Level.CONFIG)){
字串 reqlog = getRequestParametersInfo(request);
logger.config(“HTTP請求參數” + reqlog);
}
如果(logger.isLoggable(Level.CONFIG)){
logger.config(“請求範圍物件”
+ getRequestAttributeInfo(請求));
}
如果(logger.isLoggable(Level.CONFIG)){
字串 sessionlog = getSessionInfo(request,true);
logger.config(“會話範圍物件(請求處理之前)”
+ 會話日誌);
}
// 呼叫下一個過濾器
chain.doFilter(請求,回應);
// - - - - - - - - - - “後製”
如果(logger.isLoggable(Level.CONFIG)){
字串 sessionlog = getSessionInfo(request,false);
logger.config(“會話範圍物件(請求處理後)”
+ 會話日誌);
}
// 記憶體使用情況
如果(logger.isLoggable(Level.CONFIG)){
actionMemory = 」請求前後的記憶體使用情況”+LINE_SEPA
+ 動作內存 + LINE_SEPA
+ getMemoryInfo(” ” + new Time(System.currentTimeMillis())
+“請求[之後]”);
logger.config(actionMemory+LINE_SEPA);
}
// 螢幕轉換訊息
如果 (logger.isLoggable(Level.INFO)) {
String nextPage = (String) request.getAttribute(NEXT_PAGE);
if (nextPage == null || nextPage.length() == 0) {
下一頁 = request.getRequestURI();
}
logger.info(“NEXT_PAGE=[” + nextPage + “], ”
+ “IP_ADDRESS=[” + request.getRemoteAddr() + “], ”
+ “SESSION_ID=[” + request.getSession().getId() + “], ”
+ “USER-AGENT=[” + request.getHeader(“用戶代理”) + “]”);
}
如果(logger.isLoggable(Level.CONFIG)){
記錄器.config(
“============請求結束!!”
+”線程ID:”+ Thread.currentThread().hashCode()
+ ” =========================================================”
+LINE_SEPA+LINE_SEPA);
}
}
/**
*
*/
公共無效銷毀(){
}
// ---------- 下面的私有方法 --------------
私有靜態 String getMemoryInfo(String message) {
DecimalFormat dFromat = new DecimalFormat(“#,###KB”);
長空閒 = Runtime.getRuntime().freeMemory() / 1024;
長總計 = Runtime.getRuntime().totalMemory() / 1024;
長最大值 = Runtime.getRuntime().maxMemory() / 1024;
使用時間長=總計-免費;
String msg = 訊息 + ” : ” + “total=” + dFromat.format(total) + “, ”
+ “已使用量=” + dFromat.format(已使用) + ” (” + (已使用 * 100 / 總計)
+ “%), 最大可用=” + dFromat.format(max);
返回訊息;
}
/**
* 將所有請求頭輸出到日誌中。
*/
私人靜態字串 getHeadersInfo(HttpServletRequest 請求) {
StringBuffer buff = new StringBuffer(LINE_SEPA);
枚舉 headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
buff.append(“”);
buff.append(headerName);
buff.append(“=”);
buff.append(request.getHeader(headerName));
buff.append(LINE_SEPA);
}
返回 buff.toString();
}
私人靜態字串 getCookieInfo(HttpServletRequest 請求) {
StringBuffer buff = new StringBuffer();
Cookie[] cookies = request.getCookies();
if (cookies == null) {
返回 ””;
}
for (int i = 0; i < cookies.length; i++) {
buff.append(“\n — Cookie[” + i + “] —\n”);
buff.append(“”);
buff.append(cookies[i].getName());
buff.append(“=”);
buff.append(cookies[i].getValue());
buff.append(LINE_SEPA);
buff.append(“”);
buff.append(“getVersion()”);
buff.append(“=”);
buff.append(cookies[i].getVersion());
buff.append(LINE_SEPA);
buff.append(“”);
buff.append(“getComment()”);
buff.append(“=”);
buff.append(cookies[i].getComment());
buff.append(LINE_SEPA);
buff.append(“”);
buff.append(“getDomain()”);
buff.append(“=”);
buff.append(cookies[i].getDomain());
buff.append(LINE_SEPA);
buff.append(“”);
buff.append(“getMaxAge()”);
buff.append(“=”);
buff.append(cookies[i].getMaxAge());
buff.append(LINE_SEPA);
buff.append(“”);
buff.append(“getPath()”);
buff.append(“=”);
buff.append(cookies[i].getPath());
buff.append(LINE_SEPA);
buff.append(“”);
buff.append(“getSecure()”);
buff.append(“=”);
buff.append(cookies[i].getSecure());
buff.append(LINE_SEPA);
}
返回 buff.toString();
}
私人靜態字串 getRequestParametersInfo(HttpServletRequest 請求) {
StringBuffer buff = new StringBuffer(LINE_SEPA);
地圖map=convertRequest(request);
TreeMap trr = new TreeMap(map);
迭代器 itr = trr.keySet().iterator();
while (itr.hasNext()) {
字串鍵 = (字串) itr.next();
buff.append(“”);
buff.append(key);
buff.append(“=”);
物件值=map.get(key);
String[]值=(String[])值;
if (values.length == 1) {
buff.append(值[0]);
} 別的 {
// 字串陣列轉換
字串 strValue = 層(值);
buff.append(strValue);
}
buff.append(LINE_SEPA);
}
返回 buff.toString();
}
私人靜態字串 getRequestAttributeInfo(HttpServletRequest 請求) {
StringBuffer buff = new StringBuffer(LINE_SEPA);
枚舉 e = request.getAttributeNames();
while (e.hasMoreElements()) {
字串名稱 = (String) e.nextElement();
buff.append(” 名稱=” + 名稱 + “, attributeClass= ”
+ request.getAttribute(name).getClass().getName()
+ “, toString() = ” + request.getAttribute(name)
+ LINE_SEPA);
}
返回 buff.toString();
}
私人靜態字串 getRequestOtherInfo(HttpServletRequest 請求) {
StringBuffer buff = new StringBuffer();
buff.append(LINE_SEPA);
buff.append(”getCharacterEncoding()=”);
buff.append(request.getCharacterEncoding());
buff.append(LINE_SEPA);
buff.append(“getContentLength()=”);
buff.append(request.getContentLength());
buff.append(LINE_SEPA);
buff.append(”getContentType()=”);
buff.append(request.getContentType());
buff.append(LINE_SEPA);
buff.append(”getLocale()=”);
buff.append(request.getLocale());
buff.append(LINE_SEPA);
buff.append(”getProtocol()=”);
buff.append(request.getProtocol());
buff.append(LINE_SEPA);
buff.append(”getRemoteAddr()=”);
buff.append(request.getRemoteAddr());
buff.append(LINE_SEPA);
buff.append(”getRemoteHost()=”);
buff.append(request.getRemoteHost());
buff.append(LINE_SEPA);
buff.append(”getScheme()=”);
buff.append(request.getScheme());
buff.append(LINE_SEPA);
buff.append(”getServerName()=”);
buff.append(request.getServerName());
buff.append(LINE_SEPA);
buff.append(”getServerPort()=”);
buff.append(request.getServerPort());
buff.append(LINE_SEPA);
buff.append(”isSecure()=”);
buff.append(request.isSecure());
buff.append(LINE_SEPA);
buff.append(”getAuthType()=”);
buff.append(request.getAuthType());
buff.append(LINE_SEPA);
buff.append(”getContextPath()=”);
buff.append(request.getContextPath());
buff.append(LINE_SEPA);
buff.append(“getMethod()=”);
buff.append(request.getMethod());
buff.append(LINE_SEPA);
buff.append(”getPathInfo()=”);
buff.append(request.getPathInfo());
buff.append(LINE_SEPA);
buff.append(“getPathTranslated()=”);
buff.append(request.getPathTranslated());
buff.append(LINE_SEPA);
buff.append(”getQueryString()=”);
buff.append(request.getQueryString());
buff.append(LINE_SEPA);
buff.append(”getRemoteUser()=”);
buff.append(request.getRemoteUser());
buff.append(LINE_SEPA);
buff.append(”getRequestedSessionId()=”);
buff.append(request.getRequestedSessionId());
buff.append(LINE_SEPA);
buff.append(“getRequestURI()=”);
buff.append(request.getRequestURI());
buff.append(LINE_SEPA);
buff.append(”getServletPath()=”);
buff.append(request.getServletPath());
buff.append(LINE_SEPA);
buff.append(”getUserPrincipal()=”);
buff.append(request.getUserPrincipal());
buff.append(LINE_SEPA);
buff.append(”isRequestedSessionIdFromCookie()=”);
buff.append(request.isRequestedSessionIdFromCookie());
buff.append(LINE_SEPA);
buff.append(”isRequestedSessionIdFromURL()=”);
buff.append(request.isRequestedSessionIdFromURL());
buff.append(LINE_SEPA);
buff.append(”isRequestedSessionIdValid()=”);
buff.append(request.isRequestedSessionIdValid());
buff.append(LINE_SEPA);
返回 buff.toString();
}
private static String getSessionInfo(HttpServletRequest request,boolean before) {
HttpSession 會話 = request.getSession();
StringBuffer buff = new StringBuffer();
buff.append(LINE_SEPA);
如果(之前){
buff.append(” session.isNew() = ” + session.isNew());
buff.append(LINE_SEPA);
buff.append(” session.getId() = ” + session.getId());
buff.append(LINE_SEPA);
}
枚舉 e = session.getAttributeNames();
while (e.hasMoreElements()) {
String sessionName = (String) e.nextElement();
String sessionClassName = session.getAttribute(sessionName)
.getClass().getName();
buff.append(” name =” + sessionName + “, value =”
+ session.getAttribute(sessionName) + “, attributeClass = ”
+ 會話類別名稱+LINE_SEPA);
}
返回 buff.toString();
}
私有靜態Hashtable ConvertRequest(HttpServletRequest請求){
Hashtable tempHash = new Hashtable();
枚舉 e = request.getParameterNames();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
String[]values=request.getParameterValues(key);
String[]參數值=new String[values.length];
for (int i = 0; i < 值.length; i++) {
參數值[i] = convUnicode(值[i]);
}
tempHash.put(key, 參數值);
}
返回臨時哈希值;
}
私人靜態字串層(物件值){
如果(值==空){
返回「空」;
} else if (value instanceof String[]) {
返回 convString((String[]) 值);
} 別的 {
傳回值.toString();
}
}
/**
* 將字串陣列 [strArray] 的內容作為字串傳回,如下所示。
*“[溫度1,溫度2,溫度3]”
* @param strArray 要計算的字串數組
* @return 轉換後的字串
*/
私有靜態字串 convString(String[] strArray) {
if (strArray == null)
返回空值;
StringBuffer buff = new StringBuffer(“[”);
for (int i = 0; i < strArray.length; i++) {
buff.append(strArray[i] + “, “);
}
buff.delete(buff.length() – 2, buff.length());
buff.append(“]”);
返回 buff.toString();
}
/**
* 將 [str] 轉換為 Unicode。
* @參數str
* @返回
*/
私有靜態字串 convUnicode(字串 str) {
if (str == null)
返回空值;
嘗試 {
傳回新字串(str.getBytes(“8859_1”),“JISAutoDetect”);
} catch (UnsupportedEncodingException e) {
拋出新的運行時異常(e);
}
}
// ———————————————————————–
靜態類別 CustomFormatter 擴充 Formatter {
靜態最終字串模式=“yyyy/MM/dd HH:mm:ss”;
公共同步字串格式(LogRecord記錄){
StringBuffer buf = new StringBuffer();
// 設定日期和時間
日期日期 = 新日期();
date.setTime(record.getMillis());
SimpleDateFormat 格式化程式 = new SimpleDateFormat(pattern);
buf.append(formatter.format(日期));
buf.append(“:”);
// 設定等級
buf.append(“[” + record.getLevel().getName() + “]”);
buf.append(“:”);
buf.append(record.getMessage());
buf.append(LINE_SEPA);
返回 buf.toString();
}
}
靜態類別 CustomConsoleHandler 擴充 StreamHandler {
公共 CustomConsoleHandler() {
極好的();
setOutputStream(System.out);
}
/**
* 發出日誌記錄。
* 最初,記錄請求被傳送到 Logger 物件。
* 該物件初始化 LogRecord 並
*重新導向至此處。
*
* @param record 日誌事件的描述。空記錄被簡單地忽略
* 並且不會發送任何通知。
*/
公共無效發布(LogRecord記錄){
超級.發布(記錄);
沖洗();
}
/**
* 重寫 StreamHandler.close 來刷新,但是
* 輸出流未關閉。換句話說,System.err 沒有關閉。
*/
公共無效關閉(){
沖洗();
}
}
}