工作经验:Java 系统记录调用日志,并且记录错误堆栈
生活随笔
收集整理的這篇文章主要介紹了
工作经验:Java 系统记录调用日志,并且记录错误堆栈
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言:現在有一個系統,主要是為了給其他系統提供數據查詢接口的,這個系統上線不會輕易更新,更不會跟隨業務系統的更新而更新(這也是有一個數據查詢接口系統的原因,解耦)。這時,這個系統就需要有一定的方便的線上查錯方式,我便想到了記錄每一次的調用日志,而且需要記錄錯誤堆棧,同時被白名單過濾的也要記錄下來。
想法
這個日志記錄,需要在每一次訪問接口時記錄一下,在有異常時將異常的堆棧信息記錄在每次訪問記錄里。這里由于要使用數據庫信息,所以選擇了 spring 的攔截器。
在攔截器拋放心之后,運行業務代碼,如果拋異常(包括自定義異常),應該在拋異常之后,記錄錯誤信息到堆棧,這時需要知道在攔截器時插入數據庫的那條記錄的 id,拿到這個id就可以直接更新數據,將堆棧記錄。這里通過 ThreadLocal 線程本地變量來記錄每一次訪問插入數據庫后返回的主鍵 id。
而每一次的異常都需要做統一異常處理,在統一異常處理這里訪問數據庫,記錄錯誤信息。
白名單被過濾的也要記錄下來,這個利用拋自定義業務異常,然后使用統一異常類來處理就好。
實現
? 接口調用日志需要一張表來記錄,字段如下:
create table t_interface_log (id number not null,interface_name varchar2(100),caller_ip varchar2(100),local_ip varchar2(100),caller_params varchar2(1000),caller_date date,msg varchar2(4000),status varchar2(1) ) ; -- Add comments to the table comment on table t_interface_logis '接口調用日志記錄表'; -- Add comments to the columns comment on column t_interface_log.idis '主鍵id'; comment on column t_interface_log.interface_nameis '接口名'; comment on column t_interface_log.caller_ipis '調用者ip'; comment on column t_interface_log.local_ipis '本機ip'; comment on column t_interface_log.caller_paramsis '調用參數'; comment on column t_interface_log.caller_dateis '調用時間'; comment on column t_interface_log.msgis '信息記錄'; comment on column t_interface_log.statusis '狀態:0:失敗,1:成功';
配置如下:
<bean id="interfaceLogInterceptor" class="com.yule.common.interceptor.InterfaceLogInterceptor" /><mvc:interceptors><mvc:interceptor><mvc:mapping path="/interface/**"/><ref bean="interfaceLogInterceptor" /></mvc:interceptor></mvc:interceptors>
Java 代碼如下:
線程變量
package com.yule.manage.interfacelog.entity;/*** 接口調用日志線程變量* @author yule*/ public class InterfaceLogHolder {/*** 本地線程變量,用于控制每一次新增日志后返回的id*/private static final ThreadLocal<String> ID_STRING_THREAD_LOCAL = new ThreadLocal<>();/*** 獲取本地線程變量的id* @return id*/public static String getIdStringThreadLocalValue() {return ID_STRING_THREAD_LOCAL.get();}/*** 設置本地線程變量的id* @param value id*/public static void setIdStringThreadLocalValue(String value) {ID_STRING_THREAD_LOCAL.set(value);}/*** 移除當前線程的當前本地線程變量*/public static void removeStringThreadLocal() {ID_STRING_THREAD_LOCAL.remove();}}
攔截器
package com.yule.common.interceptor;import com.ch.common.util.CommonTool; import com.yule.manage.interfacelog.entity.InterfaceLog; import com.yule.manage.interfacelog.entity.InterfaceLogHolder; import com.yule.manage.interfacelog.service.InterfaceLogService; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map;/*** 日志攔截器:記錄調用日志* @author yule*/ public class InterfaceLogInterceptor extends HandlerInterceptorAdapter {@Autowiredprivate InterfaceLogService interfaceLogService;private final Logger logger = LoggerFactory.getLogger(InterfaceLogInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {try{InterfaceLog interfaceLog = new InterfaceLog();interfaceLog.setStatus(InterfaceLog.STATUS_SUCCESS);//方法返回發出請求的客戶機的IP地址 interfaceLog.setCallerIp(request.getRemoteAddr());interfaceLog.setInterfaceName(request.getRequestURI());// interfaceLog.setLocalIp(request.getLocalAddr());// 方法返回WEB服務器的IP地址。//返回一個包含請求消息中的所有參數名的Enumeration對象。通過遍歷這個Enumeration對象,就可以獲取請求消息中所有的參數名。Map<String, String[]> paramsMap = request.getParameterMap();if(CommonTool.isNotNullOrBlock(paramsMap)){StringBuilder stringBuilder = new StringBuilder();for(Map.Entry<String, String[]> entry : paramsMap.entrySet()){stringBuilder.append(entry.getKey()).append(": ").append(StringUtils.join(entry.getValue())).append("; ");}interfaceLog.setCallerParams(stringBuilder.toString());}this.interfaceLogService.insert(interfaceLog);//線程變量存值 InterfaceLogHolder.setIdStringThreadLocalValue(interfaceLog.getId());} catch (Exception e) {logger.error("接口調用記錄錯誤信息出錯;調用者ip:" + request.getRemoteHost() + ", 調用者ip:" + request.getRemoteAddr() + ", 接口名:" + request.getRequestURI(), e);}return true;} }
統一異常處理
package com.yule.common.dealexception;import com.yule.common.entity.ResponseBase; import com.yule.manage.interfacelog.entity.InterfaceLog; import com.yule.manage.interfacelog.entity.InterfaceLogHolder; import com.yule.manage.interfacelog.service.InterfaceLogService; import com.yule.interfacepackage.pibdata.web.ctrl.PibDataCtrl; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;/*** 接口 統一異常處理,并記錄錯誤日志* @author yule*/ @ControllerAdvice("com.yule.interfacepackage") public class DealInterfaceException {@Autowiredprivate InterfaceLogService interfaceLogService;private Logger logger = LoggerFactory.getLogger(DealInterfaceException .class);@ExceptionHandler@ResponseBodypublic ResponseBase dealException(HttpServletRequest request, Exception ex) {//異常處理 logger.error(ex.getMessage(), ex);ResponseBase responseBase = new ResponseBase();responseBase.setErrorMsg(ex.getMessage());responseBase.setSuccess(false);this.interfaceLogService.update(ExceptionUtils.getStackTrace(ex), InterfaceLog.STATUS_ERROR, InterfaceLogHolder.getIdStringThreadLocalValue());return responseBase;} }
?
轉載于:https://www.cnblogs.com/yuxiaole/p/9230746.html
總結
以上是生活随笔為你收集整理的工作经验:Java 系统记录调用日志,并且记录错误堆栈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 卵巢早衰性不孕症的症状
- 下一篇: Js时间格式[转载]