使用 Java 日誌過濾器解析 HTTP 請求
javax.servlet.Filter它實作了一個方便的工具,可以解析 HTTP 請求的內容並輸出日誌。篩選讓我來介紹一下這門課。
此日誌過濾器使用“java.util.logging.Logger”進行日誌輸出,您可以透過更改日誌等級來更改輸出的資訊。
什麼是 javax.servlet.Filter?
在建立 Web 應用程式時,除了主要業務流程之外,還需要執行在這些流程之前和之後常見的輔助流程。
例如,客戶端身份驗證、權限檢查、日誌記錄等。
在每個資源中編寫此類輔助進程是軟體可維護性的一個主要障礙,會導致應用程式難以維護。
透過實作 javax.servlet.Filter,可以在將請求傳遞給 servlet 類別之前執行此輔助處理。
此外,由於過濾器設定可以在 web.xml 中配置,因此您可以靈活地新增或刪除過濾器,而無需更改原始程式碼。
讓我們來試試使用日誌過濾器。
讓我們使用日誌過濾器來分析 HTTP 請求,方法是對其進行過濾。
這次湯姆貓我們將使用預設包含的範例應用程式。
完成以下設定後,即可立即執行此過濾器。
日誌過濾器日誌過濾器日誌等級美好的日誌過濾器/*
*使用 Struts 框架時的 URL 模式如下:
*。做
請在執行「會話範例」畫面時檢查日誌輸出結果。

日誌訊息輸出和日誌級別
●日誌輸出內容
| 日誌資訊 | 日誌等級 |
|---|---|
| Cookie 資訊 | 美好的 |
| HTTP 標頭資訊 | 美好的 |
| HTTP 和其他資訊 | 美好的 |
| HTTP 請求參數 | 配置 |
| 請求作用域對象 | 配置 |
| 會話作用域對象 | 配置 |
| 請求前後的記憶體使用情況 | 配置 |
| 螢幕過渡訊息 | 資訊 |
您應該使用以下日誌等級來區分它們。
- 精細設定…輸出最詳細的日誌。當您想要詳細分析 HTTP 請求時,請啟用此選項。
- CONFIG... 輸出更詳細的日誌。在開發過程中,最好保持此等級。
- 資訊……僅輸出螢幕過渡資訊。
● 如何更改日誌等級
您可以透過設定初始化參數 logging.Level 來變更日誌輸出等級。
例子:
日誌等級資訊
原始碼
導入 javax.servlet.Filter;
導入 javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
導入 javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 實作 javax.servlet.Filter 來解析 HTTP 請求的內容並輸出日誌。
* 過濾器類別。
*/
public class LogFilter implements Filter {
私人靜態日誌記錄器 logger =
Logger.getLogger(LogFilter.class.getName());
private static final String LINE_SEPA =
System.getProperty(“line.separator”);
private static final String NEXT_PAGE = “LogFilter.NEXT_PAGE”;
/**
* 初始化此日誌過濾器。
* @param 映射
*/
public void init(FilterConfig mapping) {
String str = mapping.getInitParameter(“logging.Level”);
System.out.println("將日誌等級設為 " + str + "。");
等級 level = null;
嘗試 {
level = Level.parse(str);
} catch (Exception e) {
e.printStackTrace();
level = Level.INFO;
}
LogManager.getLogManager().reset();
Handler handler = new CustomConsoleHandler();
handler.setFormatter(new CustomFormatter());
handler.setLevel(level);
日誌記錄器.setLevel(level);
logger.getParent().addHandler(處理程序);
}
/**
這是一個輸出日誌的過濾器。
* @param request 正在處理的 HTTP 請求
* @param response 正在產生的 HTTP 回應
* @param 鏈
*/
public void doFilter(ServletRequest _request, ServletResponse _response,
FilterChain 鏈) 拋出 IOException、ServletException {
// —————————————————————‘預處理’
HttpServletRequest request = (HttpServletRequest) _request;
HttpServletResponse response = (HttpServletResponse) _response;
如果 (logger.isLoggable(Level.CONFIG)) {
logger.Config(
“============ 請求開始!!”
+”線程 ID:”
+ Thread.currentThread().hashCode()
+ ” =============================================================” 版權所有;
}
// 記憶體使用情況
String actionMemory = null;
如果 (logger.isLoggable(Level.CONFIG)) {
actionMemory = getMemoryInfo(” ”
+ new Time(System.currentTimeMillis()) + " 請求 [上一次]");
}
如果 (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)) {
String reqlog = getRequestParametersInfo(request);
logger.config("HTTP 請求參數" + reqlog);
}
如果 (logger.isLoggable(Level.CONFIG)) {
logger.config("請求作用域物件")“
+ getRequestAttributeInfo(request));
}
如果 (logger.isLoggable(Level.CONFIG)) {
String sessionlog = getSessionInfo(request,true);
logger.config("會話作用域物件(請求處理之前)")“
+ 會話日誌);;
}
// 呼叫以下過濾器
chain.doFilter(請求, 回應);
// ———————————————————-‘後製’
如果 (logger.isLoggable(Level.CONFIG)) {
String sessionlog = getSessionInfo(request,false);
logger.config("會話作用域物件(請求處理後)")“
+ 會話日誌);;
}
// 記憶體使用情況
如果 (logger.isLoggable(Level.CONFIG)) {
actionMemory = "請求前後的記憶體使用" + LINE_SEPA
+ actionMemory + 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) {
nextPage = request.getRequestURI();
}
logger.info(“NEXT_PAGE=[” + nextPage + “], ”
+ “IP_ADDRESS=[” + request.getRemoteAddr() + “], ”
+ “SESSION_ID=[” + request.getSession().getId() + “], ”
+ “USER-AGENT=[” + request.getHeader(“user-agent”) + “]”);
}
如果 (logger.isLoggable(Level.CONFIG)) {
logger.Config(
“============ 請求結束!!”
+「線程 ID:」+ Thread.currentThread().hashCode()
+ ” ===========================================================”
+LINE_SEPA+LINE_SEPA);
}
}
/**
*
*/
public void destroy() {
}
// ------- 以下為私有方法 -------
private static String getMemoryInfo(String message) {
DecimalFormat dFromat = new DecimalFormat(“#,###KB”);
long free = Runtime.getRuntime().freeMemory() / 1024;
長總計 = Runtime.getRuntime().totalMemory() / 1024;
長最大值 = Runtime.getRuntime().maxMemory() / 1024;
長期使用 = 總計 – 免費;;
String msg = message + ": " + "Total=" + dFromat.format(total) + ", "”
+ “使用量=" + dFromat.format(used) + ” (” + (used * 100 / total)
+ “%”,最大可用值為” + dFromat.format(max);
返回訊息;;
}
/**
* 記錄所有請求頭。
*/
private static String getHeadersInfo(HttpServletRequest request) {
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);
}
return buff.toString();
}
private static String getCookieInfo(HttpServletRequest request) {
StringBuffer buff = new StringBuffer();
Cookie[] cookies = request.getCookies();
如果 (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);
}
return buff.toString();
}
private static String getRequestParametersInfo(HttpServletRequest request) {
StringBuffer buff = new StringBuffer(LINE_SEPA);
Map map = convertRequest(request);
TreeMap trr = new TreeMap(map);
Iterator itr = trr.keySet().iterator();
while (itr.hasNext()) {
String key = (String) itr.next();
buff.append("");
buff.append(key);
buff.append("=");
物件值 = map.get(key);
String[] values = (String[]) value;
if (values.length == 1) {
buff.append(values[0]);
別的 {
// 轉換字串陣列。
String strValue = stratum(values);
buff.append(strValue);
}
buff.append(LINE_SEPA);
}
return buff.toString();
}
private static String getRequestAttributeInfo(HttpServletRequest request) {
StringBuffer buff = new StringBuffer(LINE_SEPA);
枚舉 e = request.getAttributeNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
buff.append(” name=” + name + “, attributeClass= ”
+ request.getAttribute(name).getClass().getName()
+ “, toString() = ” + request.getAttribute(name)
+ LINE_SEPA);
}
return buff.toString();
}
private static String getRequestOtherInfo(HttpServletRequest request) {
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);
return buff.toString();
}
private static String getSessionInfo(HttpServletRequest request,boolean before) {
HttpSession session = 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 = ”
+ sessionClassName+LINE_SEPA);
}
return buff.toString();
}
private static Hashtable convertRequest(HttpServletRequest request) {
Hashtable tempHash = new Hashtable();
枚舉 e = request.getParameterNames();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
String[] values = request.getParameterValues(key);
String[] parameterValues = new String[values.length];
for (int i = 0; i < values.length; i++) {
parameterValues[i] = convUnicode(values[i]);
}
tempHash.put(key, parameterValues);
}
返回臨時哈希;;
}
private static String stratum(Object value) {
如果 (value == null) {
返回“null”;;
} else if (value instanceof String[]) {
返回 convString((String[]) 值);
別的 {
return value.toString();
}
}
/**
* 將字串陣列 [strArray] 的內容作為字串傳回,如下所示。
* “[temp1,temp2,temp3]”
* @param strArray 要計算的字串陣列。
* @return 轉換後的字串
*/
private static String convString(String[] strArray) {
如果 (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("]");
return buff.toString();
}
/**
* 將 [str] 轉換為 Unicode。
* @param str
* @返回
*/
private static String convUnicode(String str) {
如果 (str == null)
返回空值;;
嘗試 {
return new String(str.getBytes(“8859_1”), “JISAutoDetect”);
} catch (UnsupportedEncodingException e) {
拋出新的 RuntimeException(e);;
}
}
// —————————————————————————–
靜態類別 CustomFormatter 繼承自 Formatter {
static final String pattern = “yyyy/MM/dd HH:mm:ss”;
public synchronized String format(LogRecord record) {
StringBuffer buf = new StringBuffer();
// 設定日期和時間
Date date = new Date();
date.setTime(record.getMillis());
SimpleDateFormat formatter = new SimpleDateFormat(pattern);
buf.append(formatter.format(date));
buf.append(":");
// 設定等級
buf.append(“[” + record.getLevel().getName() + “]”);
buf.append(":");
buf.append(record.getMessage());
buf.append(LINE_SEPA);
return buf.toString();
}
}
static class CustomConsoleHandler extends StreamHandler {
public CustomConsoleHandler() {
極好的();
設定輸出流(System.out);
}
/**
* 將發出一個日誌記錄。
* 在初始狀態下,日誌記錄請求會定向到 Logger 物件。
這是響應操作,此物件初始化 LogRecord。
* 此內容已轉寄至此。
*
* @param record 日誌事件的描述。空記錄將被忽略。
* 不會發送任何通知。
*/
public void publish(LogRecord record) {
super.publish(record);
重新整理();
}
/**
即使你重寫了 StreamHandler.close 來刷新,
輸出流不會關閉。換句話說,System.err 不會被關閉。
*/
public void close() {
重新整理();
}
}
}
