从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(十二)日志篇(1):rocketmq+ aop +自定义注解 实现入参出参日志收集记录 完整源码

简介: 从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(十二)日志篇(1):rocketmq+ aop +自定义注解 实现入参出参日志收集记录 完整源码

edc5c4e10b854e7eb0dbe5fc9214322a.png

入参出参日志

我们日常开发中日志是不可缺少的一部分,

如mini-cloud架构图所示,大型系统一般可用elk 等进行日志收集

中小型系统也可以用spring-boot-admin 等进行收集,但我们业务场景经常

会有一种需求,就是一些重要入参出参接口希望按照url 进行收集并便于以后排查分析

比较典型的就是金融产品或者银行产品扣款,出账,转账,扣款等

期望效果

我们可能会希望通过一个url 或者关联参数定位查询某接口入参出参,比如转账例子,我们希望单独看转账接口得入出参日志

url: /transfer

args: {"transfer":1,"amount":200,"to":2}

response: {"status":200,"msg":"转账成功"}

keyword:{"转账"}

description:"转账接口记录"

架构图eb58220dbfd7425b987f201f98399c06.png

源码

共通部分aop+自定义注解

我们在共同中添加common-log模块,并添加spring.factories 自动注入,目录结构如下:

d4824fcd18c14a5da4061cab6f1d5d55.png

pom.xml

1.    <dependencies>
        <!--web 模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!--rocketmq依赖-->
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
    </dependencies>


IOLogRecordDTO.java

@Builder
@Getter
@Setter
public class IOLogRecordDTO implements Serializable {
    private Long timestamp ;
    private String method;
    private String url ;
    private String contentType;
    private String args ;
    private Object response ;
    private String dateTime;
    private String keyword ;
    private String description;
}

IOLogRecorder.java

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface IOLogRecorder {
    String keyword() default "";
    String descrition() default "";
}

IOLogAspect.java

@Aspect
public class IOLogAspect {
    @Autowired
    RocketMQTemplate rocketMQTemplate;
    @Pointcut("@annotation(com.minicloud.common.log.annotation.IOLogRecorder)")
    public void pointCut() {
    }
    @Around("pointCut()")
    public Object record(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String url = request.getRequestURI();
        String contentType= request.getHeader("content-type");
        String method = request.getMethod();
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        IOLogRecorder ioLogRecorder = methodSignature.getMethod().getAnnotation(IOLogRecorder.class);
        System.out.println(methodSignature.getMethod().getName());
        Object[] args = joinPoint.getArgs();
        String inArgs = JSONUtil.toJsonStr(args);
        Object response =  joinPoint.proceed();
        long timestamp = System.nanoTime();
        IOLogRecordDTO ioLogRecordDTO = IOLogRecordDTO.builder().keyword(ioLogRecorder.keyword()).description(ioLogRecorder.descrition()).url(url).contentType(contentType).method(method).args(inArgs).response(response).dateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))).timestamp(timestamp).build();
        rocketMQTemplate.send("iolog", MessageBuilder.withPayload(ioLogRecordDTO).build());
        return response;
    }
}

IOLogConfigration.java

@Configuration
public class IOLogConfigration {
    @Bean
    public IOLogAspect ioLogAspect(){
        return new IOLogAspect();
    }
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.minicloud.common.log.config.IOLogConfigration

rockemq搭建

本篇暂时不提及rocketmq搭建,因为涉及内容太多,会有单独篇幅介绍

日志数据库创建

日志存储可以是数据库,文件,缓存等,本篇使用的是mysql数据库


a87075e28cdc4f6d818f7b89bcb96618.png

CREATE TABLE `iolog` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '住建',
  `timestamp` bigint(20) DEFAULT NULL COMMENT '时间戳',
  `method` varchar(10) DEFAULT '' COMMENT '请求方式',
  `url` varchar(100) DEFAULT NULL COMMENT '请求url',
  `content_type` varchar(30) DEFAULT '' COMMENT '数据类型',
  `args` varchar(500) DEFAULT '' COMMENT '请求参数',
  `response` varchar(1000) DEFAULT '' COMMENT '响应',
  `data_time` varchar(30) DEFAULT '' COMMENT '日志时间',
  `keyword` varchar(50) DEFAULT '' COMMENT '关键字',
  `description` varchar(100) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4;

mq 消费端搭建

mq消费端是一个独立的mq服务,因为以后还需要集成别的消费业务,所以独立消费端便于扩展,不与具体某业务服务耦合,具体代码如下:


3b424494773340f8a79a6108beb3b76f.png

pom.xml

    <dependencies>
        <!--注册中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--配置中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--日志拦截依赖-->
        <dependency>
            <groupId>org.mini-cloud</groupId>
            <artifactId>mini-cloud-common-log</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.mini-cloud</groupId>
            <artifactId>mini-cloud-common-fegin</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <!--common data 依赖 -->
        <dependency>
            <groupId>org.mini-cloud</groupId>
            <artifactId>mini-cloud-common-data</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.mini-cloud</groupId>
            <artifactId>mini-cloud-common-auth</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

IOLogConsumer.java

@Component
@RocketMQMessageListener(consumerGroup = "group-a", topic = "iolog",consumeMode = ConsumeMode.ORDERLY)
public class IOLogConsumer implements RocketMQListener<String> {
    @Autowired
    private IOLogRecordDao ioLogRecordDao;
    @Override
    public void onMessage(String message) {
        IOLogRecordDTO ioLogRecordDTO = JSONUtil.toBean(message,IOLogRecordDTO.class);
        ioLogRecordDao.insert(ioLogRecordDTO);
    }
}

MiniCloudLogConsumerApplication.java

@SpringCloudApplication
@EnableCaching
@EnableMiniCloudFeignClients
@EnableMiniCloudResourceServer
public class MiniCloudLogConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(MiniCloudLogConsumerApplication.class, args);
    }
}

nacos 中 mini-cloud-log-consumer-dev.yml

server:
  port: 6600
  tomcat:
    uri-encoding: UTF-8
    max-threads: 500
    max-connections: 10000
    accept-count: 500
spring:
  shardingsphere:
    props:
      sql:
        show: true
    datasource:
      names: master,slave0,slave1
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://${MYSQL_HOST:192.168.1.2}:${MYSQL_PORT:3306}/${MYSQL_DB:mini_cloud_log}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
        username: root
        password: root
      slave0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://${MYSQL_HOST:192.168.1.2}:${MYSQL_PORT:3306}/${MYSQL_DB:mini_cloud_log}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
        username: root
        password: root
      slave1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://${MYSQL_HOST:192.168.1.2}:${MYSQL_PORT:3306}/${MYSQL_DB:mini_cloud_log}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
        username: root
        password: root
    sharding:
      master-slave-rules:
        master:
          master-data-source-name: master
          slave-data-source-names: slave0,slave1

服务日志发送方集成

日志发送方其实就是实际的各个业务端服务,本文在upms 服务的一个角色分页接口加上日志注解,只要添加 @IOLogRecorder 变可自动收集入参出参发送到mq,如下:

8339929eb8aa4bdfb3c4ce6ab392c275.png

重启服务以及查看结果

我们在业务端请求一个角色分页列表接口,来看看效


191d45a75b6b43ffa405ca3558af2d45.png

业务消费端接收到消息


来看看response

{
    "headers": { }, 
    "statusCodeValue": 200, 
    "body": {
        "data": [
            {
                "roleId": 33, 
                "roleDesc": "最大权限", 
                "roleCode": "SUPER_ADMIN", 
                "roleName": "超级管理员", 
                "tenantId": 1, 
                "upmsPermDTOS": [ ]
            }, 
            {
                "roleId": 34, 
                "roleDesc": "普通用户1", 
                "roleCode": "USER1", 
                "roleName": "普通用户1", 
                "tenantId": 1, 
                "upmsPermDTOS": [ ]
            }, 
            {
                "roleId": 35, 
                "roleDesc": "普通用户2", 
                "roleCode": "USER2", 
                "roleName": "普通用户2", 
                "tenantId": 1, 
                "upmsPermDTOS": [ ]
            }
        ], 
        "total": 3, 
        "size": 10, 
        "page": 1
    }, 
    "statusCode": "OK"
}

看结果已经通过mq消费端保存到数据库里了,以后可以通过各个字段进行查询操作



相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
监控 Java 数据库
从零学 Dropwizard:手把手搭轻量 Java 微服务,告别 Spring 臃肿
Dropwizard 整合 Jetty、Jersey 等成熟组件,开箱即用,无需复杂配置。轻量高效,启动快,资源占用少,内置监控、健康检查与安全防护,搭配 Docker 部署便捷,是构建生产级 Java 微服务的极简利器。
1228 117
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
549 5
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
750 0
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
593 0
|
NoSQL Java 关系型数据库
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
本文介绍在 Spring Boot 中集成 Redis 的方法。Redis 是一种支持多种数据结构的非关系型数据库(NoSQL),具备高并发、高性能和灵活扩展的特点,适用于缓存、实时数据分析等场景。其数据以键值对形式存储,支持字符串、哈希、列表、集合等类型。通过将 Redis 与 Mysql 集群结合使用,可实现数据同步,提升系统稳定性。例如,在网站架构中优先从 Redis 获取数据,故障时回退至 Mysql,确保服务不中断。
577 0
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
|
12月前
|
负载均衡 Java API
《深入理解Spring》Spring Cloud 构建分布式系统的微服务全家桶
Spring Cloud为微服务架构提供一站式解决方案,涵盖服务注册、配置管理、负载均衡、熔断限流等核心功能,助力开发者构建高可用、易扩展的分布式系统,并持续向云原生演进。
|
Prometheus 监控 Java
日志收集和Spring 微服务监控的最佳实践
在微服务架构中,日志记录与监控对系统稳定性、问题排查和性能优化至关重要。本文介绍了在 Spring 微服务中实现高效日志记录与监控的最佳实践,涵盖日志级别选择、结构化日志、集中记录、服务ID跟踪、上下文信息添加、日志轮转,以及使用 Spring Boot Actuator、Micrometer、Prometheus、Grafana、ELK 堆栈等工具进行监控与可视化。通过这些方法,可提升系统的可观测性与运维效率。
1086 1
日志收集和Spring 微服务监控的最佳实践
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
2009 5
|
机器学习/深度学习 XML Java
【spring boot logback】日志logback格式解析
在 Spring Boot 中,Logback 是默认的日志框架,它支持灵活的日志格式配置。通过配置 logback.xml 文件,可以定义日志的输出格式、日志级别、日志文件路径等。
2133 5