springboot项目日志优化(整合logback框架)

为了更好的追踪和查看http请求信息,包括请求状态,参数,以及响应报文,因此定义aop切面,按照一定格式打印出controller层请求信息和响应报文信息,项目日志框架为log back 案例代码如下:

package com.eno.config.aop;

import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.csrcb.fdm.common.util.JsonUtil;

import io.swagger.annotations.ApiOperation;

/**
 * 
 * @ClassName: LogConfig
 * @Description: 日志打印切面
 * @author eno
 * @date :2019年11月25日 下午12:15:37
 */
@Aspect
@Component
public class LogConfig {

	private static final Logger logger = LoggerFactory.getLogger(LogConfig.class);

	/**
	 * @param pjp
	 * @return
	 * @throws Throwable
	 * @Title:doAround
	 * @Description: 环绕触发
	 */
	@Around("execution(* com.csrcb.fdm.core.controller..*.*(..))")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();
		String inputParam = getMethodParams(pjp);
		// 获取请求地址
		String requestPath = request.getRequestURL().toString();
		// 设定mdc 信息
		//MDC.put("taskName", getAnnotaion(pjp));

		String contentType = request.getContentType();
		Instant startTime = Instant.now();
		// 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
		StringBuffer requestSb = new StringBuffer();
		requestSb.append("==>访问接口地址:").append(requestPath).append("  请求头Content-Type:").append(contentType)
				.append("  请求参数:{\"request\":").append(inputParam).append("}");
		logger.info(requestSb.toString());
		Object obj = pjp.proceed();
		// result的值就是被拦截方法的返回值
		String result = obj instanceof String ? (String) obj : JsonUtil.object2Json(obj);
		Instant endTime = Instant.now();
		long proTime = Duration.between(startTime, endTime).toMillis();
		StringBuffer responseSb = new StringBuffer();
		responseSb.append("==>接口耗时:").append(proTime).append("ms").append(" 响应参数:{\"result\":").append(result)
				.append("}");
		logger.info(responseSb.toString());
		// 清理mdc 容器
		/*try {
			MDC.clear();
		} catch (Exception e) {
			logger.error("clear mdc error {}", e);
		}*/
		return obj;
	}

	/**
	 * 打印类method的名称以及参数
	 *
	 * @param point 切面
	 */
	public String getMethodParams(ProceedingJoinPoint point) {
		if (point == null) {
			return null;
		}
		// 获取方法的参数值数组。
		Object[] methodGrgs = point.getArgs();
		try {
			// 获取方法参数名称
			String[] paramNames = ((CodeSignature) point.getSignature()).getParameterNames();
			// 打印方法的参数名和参数值
			return logParam(paramNames, methodGrgs);
		} catch (Exception e) {
			logger.error("获取参数异常", e);
		}
		return null;
	}

	/**
	 * 判断是否为基本类型:包括String
	 *
	 * @param clazz clazz
	 * @return true:是; false:不是
	 */
	private boolean isPrimite(Class<?> clazz) {
		if (clazz.isPrimitive() || clazz == String.class) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 打印方法参数值 基本类型直接打印,非基本类型需要转成json字符串方法
	 *
	 * @param paramsArgsName  方法参数名数组
	 * @param paramsArgsValue 方法参数值数组
	 * @return
	 */
	private String logParam(String[] paramsArgsName, Object[] paramsArgsValue) {
		if (ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)) {
			logger.info("该方法没有参数");
			return null;
		}
		StringBuffer buffer = new StringBuffer();
		for (int i = 0; i < paramsArgsName.length; i++) {
			// 参数名
			String name = paramsArgsName[i];
			// 参数值
			Object value = paramsArgsValue[i];
			buffer.append(name + " = ");
			if (isPrimite(value.getClass())) {
				buffer.append(value + "  ,");
			} else {
				buffer.append(JsonUtil.object2Json(value) + "  ,");
			}
		}
		return StringUtils.removeEndIgnoreCase(buffer.toString(), "  ,");
	}

	/**
	 * 获取ApiOperation 注解值
	 * @param point
	 * @return
	 * @throws SecurityException 
	 * @throws Exception 
	 */
	private String getAnnotaion(ProceedingJoinPoint pjp) throws Throwable {
		MethodSignature msg = (MethodSignature) pjp.getSignature();
		Object target = pjp.getTarget();
		// 获取注解标注方法
		Method method = target.getClass().getMethod(msg.getName(), msg.getParameterTypes());
		// 获取注解对象
		ApiOperation annotation = method.getAnnotation(ApiOperation.class);
		if (annotation != null) {
			return annotation.value();
		}
		return null;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章