Springboot入门之线上日志处理

日志的作用

1.故障排查:通过日志可对系统进行实时健康度监控,系统日志记录程序 Syslog 就是为这个目的而设计的。

2.数据分析:通过对业务系统日志进行关联分析,可以掌握业务系统的整体运行情况,并可通过日志进一步掌握用户画像、用户访问地域、用户访问热点资源等信息,从而为业务平台的市场营销、销售策略等提供数据支撑。

3.安全合规审计:根据国家网络安全法等级保护要求,需要对安全设备日志进行集中存储和分析。

4.内网安全监控:很多企业的信息泄露源于内部,使用日志进行用户行为分析以监控内网安全,已成为行业共识。

5.智能运维:随着大数据时代的到来,数据管理和分析方案越来越智能,自动化运维已逐渐普及。机器数据作为智能运维的基础数据,必将发挥越来越重要的作用。

1.Controller层输入输出效率日志

使用AOP切面技术

/**
 * controller request and response log
 *
 * @author ocean.liu
 */
@Component
@Aspect
@Slf4j
public class ControllerLogAop {

    @Around("execution(public *  com.xx.xxx.controller.*.*(..))")
    public Object aroundApi(ProceedingJoinPoint point) throws Throwable {
        return writeLog(point);
    }

    private Object writeLog(ProceedingJoinPoint point) throws Throwable {
        String className = point.getTarget().getClass().getName();
        String methodName = point.getSignature().getName();

        String reqUrl = StringUtils.EMPTY;
        String reqMethod = StringUtils.EMPTY;

        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        if (sra != null) {
            HttpServletRequest request = sra.getRequest();
            reqUrl = request.getRequestURL().toString();
            reqMethod = request.getMethod();
        }


        long beginTime = System.currentTimeMillis();
        Object result = null;
        Exception ex = null;
        try {
            result = point.proceed();
            return result;
        } catch (Exception e) {
            ex = e;
            throw e;
        } finally {
            long costTime = System.currentTimeMillis() - beginTime;
            if (ex != null) {
                log.error("[url: {}][method: {}][className: {}][methodName: {}][cost: {} ms][args: {}][error: {}]", reqUrl, reqMethod, className, methodName, costTime, point.getArgs(), ex.getMessage());
            } else {
                log.info("[url: {}][method: {}][className: {}][methodName: {}][cost: {} ms][args: {}][return: {}]", reqUrl, reqMethod, className, methodName, costTime, point.getArgs(), result);
            }
        }
    }

}

2.Controller层异常捕获与统一返回处理

2.1)定义业务异常枚举类

public enum ErrorMsg {

    COMMON_ERROR_1("服务端异常", -1),
    COMMON_ERROR_2("参数校验异常", -2),
    BUSSINESS_ERROR_1000001("异常信息", 1000001),
    ;

    private final String msg;
    private final Integer code;

    ErrorMsg(String msg, Integer code) {
        this.msg = msg;
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public Integer getCode() {
        return code;
    }

}

2.2)定义业务异常

public class BusinessException extends RuntimeException {

    private ErrorMsg errorMsg;

    public BusinessException(ErrorMsg errorMsg) {
        super(errorMsg.getMsg());
        this.errorMsg = errorMsg;
    }

    public ErrorMsg getErrorMsg() {
        return errorMsg;
    }

}

2.3)添加异常处理类【@RestControllerAdvice】

@RestControllerAdvice
@Slf4j
public class ControllerExceptionHandler {


    /**
     * 参数校验异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    ResultVO methodArgumentNotValidExceptionHandle(MethodArgumentNotValidException e) {
        log.error("{} = {}", ErrorMsg.COMMON_ERROR_2.getMsg(), e.getMessage());
        return ResultVO.error(ErrorMsg.COMMON_ERROR_2.getCode(), e.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(Collectors.joining(",")));
    }

    /**
     * 业务异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = {BusinessException.class})
    ResultVO businessExceptionHandle(BusinessException e) {
        log.error(e.getErrorMsg().getMsg(), e);
        return ResultVO.error(e.getErrorMsg());
    }


    @ExceptionHandler(value = {Exception.class})
    ResultVO exceptionHandle(Exception e) {
        log.error("{} = {}", ErrorMsg.COMMON_ERROR_1.getMsg(), e.getMessage(), e);
        return ResultVO.error(ErrorMsg.COMMON_ERROR_1);
    }

}

3.日志追踪之链路信息

使用MDC添加链路追踪ID,本案例中使用TID代表一次请求处理的事务ID。

/**
 * MDC日志自定义实现过滤器
 *
 * @author ocean.liu
 */
@Component
public class LogMdcFilter implements Filter {

    private static final String MDC_TID_FIELD = "TID";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            MDC.put(MDC_TID_FIELD, UUID.randomUUID().toString());
            chain.doFilter(request, response);
        } finally {
            MDC.remove(MDC_TID_FIELD);
        }
    }

}

你可能感兴趣的:(SpringBoot,spring,boot)