springboot自定义注解收集操作日志

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: springboot自定义注解收集操作日志


image.png

对于日志收集,是系统离不开的功能,那么如何实现简易的日志收集呢。市面上最常见的就是使用自定义注解。本文将介绍如何使用自定义注解收集日志。

1.添加自定义注解

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /**
     * 注释
     */
    String operationName() default "";
}

2.使用AOP拦截注解

该类的含义是:没调用一个接口,都会判断该接口是否带有上文的自定义注解,如果带有,就会执行AOP中的功能,本文是获取入参,出参,sql,方法名,系统名,调用ip等参数,并打印。

@Component
public class LogAspect {
    private Logger logger = LoggerFactory.getLogger(LogAspect.class);
    private String succeed = "true";
    /**
     * 在注释@log的方法中进入本类
     */
    @Pointcut("@annotation(com.resource.business.modular.log.annotation.Log)")
    public void logPointCut() {}
    /**
     * 前置通知 用于拦截操作,在方法返回后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
    public void doAfter(JoinPoint joinPoint, Result jsonResult) {
        handleLog(joinPoint, jsonResult);
    }
    /**
     * 拦截异常操作,有异常时执行
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfter(JoinPoint joinPoint, Exception e) {
        Log controllerLog = getAnnotationLog(joinPoint);
        // 没有注解
        if (controllerLog == null) {
            return;
        }
        // 处理入参
        String args = this.argsArrayToString(joinPoint.getArgs());
        // 获取请求上下文信息
        ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        // 获取时间
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 获取用户信息
        String userName = (String.valueOf(SecurityContextHolder.getContext().getAuthentication().getPrincipal()));
        // 组合入参信息
        logger.error("|" + userName + "|" + controllerLog.operationName() + "|" + sd.format(new Date()) + "|"
            + IpUtil.getIpAddr() + "|" + "XXX系统" + "|" + "操作日志" + "|" + "null" + "|" + "null");
        logger.error("|" + userName + "|" + controllerLog.operationName() + "|" + sd.format(new Date()) + "|"
            + IpUtil.getIpAddr() + "|" + "XXX系统" + "|" + "接口日志" + "|" + request.getRequestURI() + "|" + args);
        logger.debug("错误信息为:" + e);
    }
    /**
     * 判断是否有注解
     * 
     * @param joinPoint
     * @throws Exception
     */
    private Log getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(Log.class);
        }
        return null;
    }
    /**
     * 功能描述:执行日志操作
     *
     * @param: joinPoint ,e ,response
     * @return:
     */
    private void handleLog(final JoinPoint joinPoint, Result jsonResult) {
        Log controllerLog = getAnnotationLog(joinPoint);
        // 没有注解
        if (controllerLog == null) {
            return;
        }
        // 处理入参
        String args = this.argsArrayToString(joinPoint.getArgs());
        // 获取请求上下文信息
        ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        // 获取时间
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 获取用户信息
        String userName = (String.valueOf(SecurityContextHolder.getContext().getAuthentication().getPrincipal()));
        // 组合入参信息
        logger.info("|" + userName + "|" + controllerLog.operationName() + "|" + sd.format(new Date()) + "|"
            + IpUtil.getIpAddr() + "|" + "XXX系统" + "|" + "操作日志" + "|" + "null" + "|" + "null");
        logger.info("|" + userName + "|" + controllerLog.operationName() + "|" + sd.format(new Date()) + "|"
            + IpUtil.getIpAddr() + "|" + "XXX系统" + "|" + "接口日志" + "|" + request.getRequestURI() + "|" + args);
        logger.info("输出参数:" + JSONArray.toJSONString(jsonResult.getData()));
    }
    /**
     * 组装入参
     * 
     * @param paramsArray
     * @return
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (int i = 0; i < paramsArray.length; i++) {
                if (!isFilterObject(paramsArray[i])) {
                    Object jsonObj = JSON.toJSON(paramsArray[i]);
                    params += jsonObj.toString() + " ";
                }
            }
        }
        if (("").equals(params.trim())) {
            params = "无入参";
        }
        return params.trim();
    }
    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象,则返回true;否则返回false。
     */
    public boolean isFilterObject(final Object o) {
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
    }
}

注意:楼主使用elk收集了日志,输出在logstash中获取“|” 然后拆分成不同字段,并保存在es中,可在后续文章看到。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1月前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
52 0
|
1月前
|
Java 中间件
SpringBoot入门(6)- 添加Logback日志
SpringBoot入门(6)- 添加Logback日志
85 5
|
1月前
|
消息中间件 Java 数据库
解密Spring Boot:深入理解条件装配与条件注解
Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
36 2
|
1月前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
43 2
|
1月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
53 1
|
1月前
|
存储 安全 Java
springboot当中ConfigurationProperties注解作用跟数据库存入有啥区别
`@ConfigurationProperties`注解和数据库存储配置信息各有优劣,适用于不同的应用场景。`@ConfigurationProperties`提供了类型安全和模块化的配置管理方式,适合静态和简单配置。而数据库存储配置信息提供了动态更新和集中管理的能力,适合需要频繁变化和集中管理的配置需求。在实际项目中,可以根据具体需求选择合适的配置管理方式,或者结合使用这两种方式,实现灵活高效的配置管理。
25 0
|
2月前
|
存储 Java 数据管理
强大!用 @Audited 注解增强 Spring Boot 应用,打造健壮的数据审计功能
本文深入介绍了如何在Spring Boot应用中使用`@Audited`注解和`spring-data-envers`实现数据审计功能,涵盖从添加依赖、配置实体类到查询审计数据的具体步骤,助力开发人员构建更加透明、合规的应用系统。
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
186 1
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
118 62
|
13天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
75 13

热门文章

最新文章