common--全局日志处理

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 操作日志和微服务场景日志统一处理

一、通过切面的方式记录请求日志信息

@Aspect
@Component
@Slf4j
@Order(1)
public class WebLogAspect {

private static final String START_TIME = "request-start";
/**
 * 服务名
 */
@Value("${spring.application.name}")
private String serverName;

@Autowired
private SaveLogInfoService logInfoService;
/**
 * 切入点
 */
@Pointcut("execution(public * com.xxx..controller..*(..))")//两个..代表所有子目录,最后括号里的两个..代表所有参数
public void log() {

}

/**
 * 前置操作
 *
 * @param point 切入点
 */
@Before("log()")
public void beforeLog(JoinPoint point) {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

    HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();

    log.info("({})【请求 URL】:{},【IP】:{}",serverName, request.getRequestURL(), IpUtils.getIpAddr(request));
    log.info("({})【请求类名】:{},【请求方法名】:{}",serverName, point.getSignature().getDeclaringTypeName(), point.getSignature().getName());
    Object[] args = point.getArgs();
    log.info("({})【请求参数】:{},", serverName,JSONUtil.toJsonStr(args));
    Long start = System.currentTimeMillis();
    request.setAttribute(START_TIME, start);
    //saveLog
    Class clazz = point.getTarget().getClass();
    String method = point.getSignature().getName();
    OperationLogBean operationLogBean=new OperationLogBean();
    operationLogBean.setMethod(method);
    operationLogBean.setIp(IpUtils.getIpAddr(request));
    operationLogBean.setClassName(point.getSignature().getDeclaringTypeName());
    operationLogBean.setReqParam(JSONUtil.toJsonStr(args));
    operationLogBean.setTraceId(MDC.get(AuthUtils.TRACE_ID));
    operationLogBean.setCreateDate(new Date());
    MethodSignature signature = (MethodSignature)point.getSignature();
    Method d = signature.getMethod();
    Annotation[] annotations = d.getDeclaredAnnotations();
    if (annotations != null) {
        for (Annotation annotation : annotations) {
            if (annotation instanceof ApiOperation) {
                ApiOperation methodDesc = (ApiOperation) annotation;
                String desc = methodDesc.value();
                operationLogBean.setMethodName(desc);
            }
        }
    }
    Annotation[] declaredAnnotations = clazz.getDeclaredAnnotations();
    if(declaredAnnotations !=null){
        for (Annotation annotation : declaredAnnotations) {
            if (annotation instanceof Api) {
                Api classDesc = (Api) annotation;
                String desc = classDesc.value();
                operationLogBean.setClassNameInfo(desc);
            }
        }
    }
    AuthTokenData auth = AuthThreadLocal.getAuth();
    if(Objects.nonNull(auth)&&Objects.nonNull(auth.getUser())){
        operationLogBean.setUserId(auth.getUser().getUserId());
        operationLogBean.setUserName(auth.getUser().getUsername());
    }
    saveLog(operationLogBean);
}

/**
 * 环绕操作
 *
 * @param point 切入点
 * @return 原方法返回值
 * @throws Throwable 异常信息
 */
@Around("log()")
public Object aroundLog(ProceedingJoinPoint point) throws Throwable {
    Object result = point.proceed();
    //log.info("【返回值】:{}", JSONUtil.toJsonStr(result));
    return result;
}

/**
 * 后置操作
 */
@AfterReturning("log()")
public void afterReturning() {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();

    Long start = (Long) request.getAttribute(START_TIME);
    Long end = System.currentTimeMillis();
    log.info("({})【耗时】:{}毫秒,【请求 URL】:{},【IP】:{}",serverName, end - start, request.getRequestURL(), IpUtils.getIpAddr(request));

    String header = request.getHeader("User-Agent");
    UserAgent userAgent = UserAgentUtil.parse(header);
    log.info("({})【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", serverName,userAgent.getBrowser().toString(), userAgent.getOs().toString(), header);
}
private void saveLog(OperationLogBean operationLogBean){
    if(Objects.nonNull(logInfoService)){
        logInfoService.save(operationLogBean);
    }
}

}

二、使用MDC统一处理微服务场景各服务间调用日志

原理就是给每一条日志打上标签,比如一次调用从网关开始,在该次请求上添加链路追踪id
image.png

被路由到的服务会全局拦截请求,获取id,放入MDC中

image.png

三、自定义logback日志打印处理类

image.png
image.png
所有的日志存储都带上来链路追踪id

feign

在feign调用的时候,可以将id传递
/**

  • @Description: feign相互调用过程中,将请求头传到被调用服务中

*/

@Component
public class FeignRequestInterceptor implements RequestInterceptor {

@Override
public void apply(RequestTemplate requestTemplate) {
    //传递日志traceId
    String traceId = MDC.get(AuthUtils.TRACE_ID);
    // 加入请求来源
    requestTemplate.header(AuthUtils.FROM, AuthUtils.GATEWAY);
    // 加入Feign调用标志
    requestTemplate.header(Global.FEIGN, Global.FEIGN);
    // 加入认证信息
    AuthTokenData auth = AuthThreadLocal.getAuth();
    if (ObjectUtils.isNotEmpty(auth)) {
        requestTemplate.header(AuthUtils.AUTH, URLUtil.encode(JsonUtils.obj2String(auth)));
    }
    if(StringUtils.isNotEmpty(traceId)){
        requestTemplate.header(AuthUtils.TRACE_ID, traceId);
    }
}

}

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
logging 日志 模块
logging 日志 模块
|
6月前
|
消息中间件 数据库 开发者
Logging模块的高级用法
【6月更文挑战第21天】 - 支持DEBUG到CRITICAL的多级日志,便于控制信息输出。 - 可自定义日志格式,包含时间戳、级别等信息。 - 使用处理程序(如FileHandler、StreamHandler)将日志发送到不同目的地。 - 通过过滤器实现日志筛选,精细化控制记录。 - 利用配置文件管理日志设置,灵活可配置。 - 实现日志轮转和归档,管理日志文件大小和期限。 - 自定义处理程序适应特殊需求,如发送到数据库或消息队列。 - 异常处理中记录日志,增强调试能力。 - 遵循最佳实践,如选择合适日志级别、保持格式一致。 - 注意性能考量,如异步记录、批量处理和优化处理程序。
|
Serverless Python
可以通过配置logging模块来记录日志
可以通过配置logging模块来记录日志
48 2
|
Python
python-logging全局日志配置-滚动删除,只保存最近7天的日志,按级别存入不同文件
最近有这样一个需求,需要记录一下用户行为,和记下一些错误日志,放入指定文件夹里不同的文件下,方便后续debug。我决定采用python logging模块。并且使用配置文件,并做一个全局的globalLog.py来使用logging。 (关键词:logging,TimedRotatingFileHandler)
844 0
python-logging全局日志配置-滚动删除,只保存最近7天的日志,按级别存入不同文件
|
XML JSON 缓存
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架(下)
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架(下)
267 0
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架(下)
|
XML Java 程序员
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架(中)
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架(中)
496 0
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架(中)
|
存储 运维 监控
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架(上)
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架
555 0
最详细、最全面的【Java日志框架】介绍,建议收藏,包含JUL、log4j、logback、log4j2等所有主流框架(上)
|
Java 微服务
自定义ApiBoot Logging链路以及单元ID
`ApiBoot Logging`会为每一个请求都对应创建链路编号(`TraceID`)以及单元编号(`SpanID`),用于归类每一次请求日志,通过一个链路下日志单元的`Parent SpanID`可以进行上下级关系的梳理。
自定义ApiBoot Logging链路以及单元ID
|
监控 Java 开发工具
使用ApiBoot Logging进行统一管理请求日志
`ApiBoot Logging`通过集成`minbox-logging`来进行管理每一次请求的日志信息,包含`头信息`、`参数`、`主体内容`、`路径`、发生的`服务器`相关信息等,根据接口的响应状态还可以记录响应的头信息、响应的内容以及发生异常时的`堆栈信息`。
|
微服务
common--全局异常处理器
微服务相关统一处理
270 0
common--全局异常处理器