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;
	}
}

 

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