git
https://github.com/haohongyaocom/bootdemo
效果
要打印前端和rpc接口调用的方法和参数以及返回结果,整个项目就可以减少很多手动的log打印,另外这些日志对运维排查问题非常有帮助
准备工作
package com.example.demo.pojo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.util.Date;
@Getter
@Setter
@ToString
public class SysLog implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private String operation;
private String method;
private String params;
private String ip;
private String resp;
private Date createDate;
}
package com.example.demo.util;
import com.alibaba.fastjson.JSON;
import com.example.demo.pojo.SysLog;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
/**
* @author hongtao.hao
* @date 2019/6/28
*/
public class LogUtil {
private static final Logger logger = LoggerFactory.getLogger(LogUtil.class);
public static SysLog getSysLog(JoinPoint joinPoint) {
SysLog sysLog = new SysLog();
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
// 请求方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
// 请求的参数
Object[] args = joinPoint.getArgs();
String params = (args == null || args.length == 0) ? null : JSON.toJSONString(args);
sysLog.setParams(params);
// 请求时间
sysLog.setCreateDate(new Date());
return sysLog;
}
public static SysLog getSysLog(JoinPoint joinPoint, Object result) {
SysLog sysLog = getSysLog(joinPoint);
sysLog.setResp(JSON.toJSONString(result));
return sysLog;
}
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
}
/**
* 获取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;
}
}
controller日志
package com.example.demo.interceptor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.alibaba.fastjson.JSON;
import com.example.demo.pojo.SysLog;
import com.example.demo.util.LogUtil;
/**
* @author hongtao.hao
* @date 2019/6/27
*/
@Aspect
@Component
public class ControllerLogAspect extends HandlerInterceptorAdapter {
private Logger logger = LoggerFactory.getLogger(getClass().getName());
// 定义Pointcut,此方法不能有返回值,该方法只是一个标示
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
public void logPointCut() {
}
@Before("logPointCut()")
public void saveSysLog(JoinPoint joinPoint) {
SysLog sysLog = LogUtil.getSysLog(joinPoint);
// 请求用户名
sysLog.setUsername(null);
logger.info(">>> " + JSON.toJSONString(sysLog));
}
@AfterReturning(returning = "result", pointcut = "logPointCut()")
public void doAfterReturning(JoinPoint joinPoint, Object result) {
SysLog sysLog = LogUtil.getSysLog(joinPoint, result);
logger.info(">>> " + JSON.toJSONString(sysLog));
}
}
service日志
rpc之类的也是必须要打印的
package com.example.demo.interceptor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.alibaba.fastjson.JSON;
import com.example.demo.pojo.SysLog;
import com.example.demo.util.LogUtil;
/**
* @author hongtao.hao
* @date 2019/6/27
*/
@Aspect
@Component
public class ServiceLogAspect extends HandlerInterceptorAdapter {
private Logger logger = LoggerFactory.getLogger(getClass().getName());
// 定义Pointcut,此方法不能有返回值,该方法只是一个标示
// @annotation 指定自定义注解:在自定义注解出现的位置切入代码
@Pointcut("execution(* com.example.demo.service.*.*(..))")
public void logPointCut() {
}
@Before("logPointCut()")
public void saveSysLog(JoinPoint joinPoint) {
SysLog sysLog = LogUtil.getSysLog(joinPoint);
logger.info(">>> " + JSON.toJSONString(sysLog));
}
@AfterReturning(returning = "result", pointcut = "logPointCut()")
public void doAfterReturning(JoinPoint joinPoint, Object result) {
SysLog sysLog = LogUtil.getSysLog(joinPoint, result);
logger.info(">>> " + JSON.toJSONString(sysLog));
}
}
自定义
拦截自定义的注解,对加了该注解的方法进行特殊的日志处理
package com.example.demo.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author hongtao.hao
* @date 2019/6/27
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MySysLog {
String value() default "";
}
package com.example.demo.interceptor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.alibaba.fastjson.JSON;
import com.example.demo.pojo.SysLog;
import com.example.demo.util.LogUtil;
/**
* 拦截自定义的MySysLog注解,进行特殊处理
*
* @author hongtao.hao
* @date 2019/6/27
*/
@Aspect
@Component
public class MySysLogAspect extends HandlerInterceptorAdapter {
private Logger logger = LoggerFactory.getLogger(getClass().getName());
// @annotation 指定自定义注解:在自定义注解出现的位置切入代码
@Pointcut("@annotation(com.example.demo.annotation.MySysLog)")
public void logPointCut() {
}
@Before("logPointCut()")
public void saveSysLog(JoinPoint joinPoint) {
}
@AfterReturning(returning = "result", pointcut = "logPointCut()")
public void doAfterReturning(JoinPoint joinPoint, Object result) {
}
}