1. 程式人生 > >renren-fast 專案解讀:系統日誌處理

renren-fast 專案解讀:系統日誌處理

系統日誌處理

  1. 系統日誌,在系統中主要是使用的是註解日誌的形式。通過註解去控制系統日誌列印的內容。
  2. 基本實現程式碼:這裡通過環繞處理

    @Pointcut("@annotation(io.renren.common.annotation.SysLog)")
    public void logPointCut() {

    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //執行方法
        Object result = point.proceed();
        //執行時長(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        //儲存日誌
        saveSysLog(point, time);
        return result;
    }
    
  1. 主要儲存資訊程式碼:通過切面獲取方法名,方法引數,獲取ip地址,使用者名稱,執行時間等,寫入到庫中。這裡使用的是mybatis,插入資料庫中。在平常我們也可以修改這裡的日誌記錄,放到mongo中或者其他地方。這裡主要還是看實際使用場景選擇技術。
private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SysLogEntity sysLog = new SysLogEntity();
        SysLog syslog = method.getAnnotation(SysLog.class);
        if (syslog != null) {
            //註解上的描
            sysLog.setOperation(syslog.value());
        }
        //請求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");
        //請求的引數
        Object[] args = joinPoint.getArgs();
        String params = new Gson().toJson(args);
        sysLog.setParams(params);
        //獲取request
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        //設定IP地址
        sysLog.setIp(IPUtils.getIpAddr(request));
        //使用者名稱
        String username = ((SysUserEntity) SecurityUtils.getSubject().getPrincipal()).getUsername();
        sysLog.setUsername(username);
        sysLog.setTime(time);
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        sysLog.setCreateDate(new Date());
        //儲存系統日誌
        sysLogService.insert(sysLog);
    }
  1. 獲取request物件。HttpContextUtils:這裡使用的Spring的上下文RequestContextHolder來獲取的HttpServletRequest,再通過request獲取相關請求資訊
public static HttpServletRequest getHttpServletRequest() {
		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
	}

  1. IPUtils:獲取真實地址ip。 這裡主要是處理代理伺服器的問題,通過代理無法獲取到真實ip。一般代理的真實地址會放到header中,所以這裡的工具類主要是通過獲取header中的引數查詢真實地址。注意這裡,在反向代理中一定要配置,新增真實ip的header
/**
	 * 獲取IP地址
	 * 
	 * 使用Nginx等反向代理軟體, 則不能通過request.getRemoteAddr()獲取IP地址
	 * 如果使用了多級反向代理的話,X-Forwarded-For的值並不止一個,而是一串IP地址,X-Forwarded-For中第一個非unknown的有效IP字串,則為真實IP地址
	 */
	public static String getIpAddr(HttpServletRequest request) {
    	String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
        	logger.error("IPUtils ERROR ", e);
        }
        return ip;
    }