# ztrace **Repository Path**: 44346460/ztrace ## Basic Information - **Project Name**: ztrace - **Description**: 基于 Spring AOP 的非侵入式事件采集与清洗框架,支持同步/异步采样、多存储介质转储、以及链式收集器处理. - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 3 - **Created**: 2021-08-05 - **Last Updated**: 2026-07-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: Java, 埋点, 采样 ## README # ZTrace — 动态事件追踪框架 [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.2.2-brightgreen)](https://spring.io/projects/spring-boot) [![JDK](https://img.shields.io/badge/JDK-1.8%2B-blue)](https://openjdk.java.net/) [![License](https://img.shields.io/badge/License-Apache%202.0-yellow.svg)](https://opensource.org/licenses/Apache-2.0) > 基于 Spring AOP 的非侵入式事件采集与清洗框架,支持同步/异步采样、多存储介质转储、以及链式收集器处理。 ## 📋 目录 - [项目背景](#项目背景) - [架构概览](#架构概览) - [核心概念](#核心概念) - [快速开始](#快速开始) - [1. 引入依赖](#1-引入依赖) - [2. 定义采样器(Sampler)](#2-定义采样器sampler) - [3. 定义收集器(Collector)](#3-定义收集器collector) - [4. 在业务方法上埋点](#4-在业务方法上埋点) - [5. 启动配置](#5-启动配置) - [配置项参考](#配置项参考) - [采样端(Client)](#采样端client) - [收集端(Server)](#收集端server) - [设计特性](#设计特性) - [存储介质说明](#存储介质说明) - [注意事项](#注意事项) --- ## 项目背景 在大多数业务系统中,**功能开发总是先行于数据埋点**。埋点需求往往在产品运营稳定后才逐步浮现——用于辅助运营决策、产品迭代分析或用户行为追踪。然而,当这些"后知后觉"的埋点需求落到已有业务代码上时,开发者通常面临两难困境: - **侵入式改动风险高**:为了插入埋点逻辑,不得不修改原本稳定的业务代码,极易引入新的 Bug,破坏既有功能。 - **埋点方式因人而异**:不同开发者对埋点的实现方式各不相同,有的直接硬编码在 Service 层,有的另起异步线程,有的通过拦截器……导致**功能性代码与非功能性代码严重耦合、混乱交织**,后期维护成本陡增。 - **重复造轮子**:每个团队、每个项目都在重复解决"如何在不改业务代码的前提下采集数据"这一相同问题。 ZTrace 正是为了解决上述痛点而设计。它基于 **Spring AOP** 提供了一套**规范化、统一化、非侵入式**的埋点方案: - 业务代码**零改动**,仅通过注解声明即可实现方法级拦截; - 采样逻辑与收集逻辑**完全解耦**,由框架统一调度,杜绝"各自为战"的埋点乱象; - 支持多种存储介质与灵活的部署方式,一套框架即可覆盖从开发测试到生产运营的全生命周期。 --- ## 架构概览 ``` ┌─────────┐ 写入样本流 ┌──────────────┐ 读取样本流 ┌───────────┐ 过滤/筛选/加工/转储 ┌──────────────┐ │ Sampler │ ──────────────→ │ IEventStorage │ ──────────────→ │ Collector │ ─────────────────────→ │ IEventStorage │ │ (采样端) │ │ (样本池) │ │ (收集端) │ │ (清洗后存储) │ └─────────┘ └──────────────┘ └───────────┘ └──────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ │ MQ │ DB │ File │ HTTP │ Redis │ Other (如第三方数据分析平台:神策、GrowingIO 等) │ └─────────────────────────────────────────────────────────────────────────────────────────┘ ``` **数据流向说明:** 1. **Sampler(采样端)**:通过 AOP 拦截业务方法,采集方法入参或返回值,组装为 `TraceEvent`,写入 **IEventStorage(样本池)** 2. **Collector(收集端)**:从样本池消费 `TraceEvent`,按 `group` 路由到对应的收集器,完成过滤、加工后,再次写入 **IEventStorage(清洗后存储)** 3. **最终存储**:清洗后的数据可落库、发往下游 MQ、调用 HTTP 接口、或写入第三方服务 > **部署灵活性**:Sampler 与 Collector 可在同一 JVM 实例中集成,也可拆分为独立服务部署。 --- ## 核心概念 | 组件 | 职责 | 关键点 | |------|------|--------| | **TraceSampler** | 定义"采什么"——从方法入参/返回值中提取业务字段 | 必须线程安全,框架会缓存实例 | | **TraceCollector** | 定义"怎么洗"——对样本做过滤、加工、转储 | 支持链式处理,按 `group` 匹配 | | **IEventStorage** | 定义"存哪里"——统一的数据转储接口 | 一套接口,两端复用(采样端 + 收集端) | | **TraceEvent** | 数据载体 | `group`(分组)+ `type`(类型)+ `properties`(属性) | --- ## 快速开始 ### 1. 引入依赖 ```xml com.hyw trace 0.0.1 ``` > 默认依赖 **Spring Cloud Stream Kafka** 作为消息中间件,请确保已配置 Kafka 连接信息。配置方式请参考 [Spring Cloud Stream 官方文档](https://spring.io/projects/spring-cloud-stream)。 --- ### 2. 定义采样器(Sampler) 实现 `TraceSampler`,从方法入参中提取需要追踪的字段: ```java @Component public class OrderSampler extends TraceSampler { @Override public Map process(OrderDTO order) { Map props = new HashMap<>(); props.put("orderId", order.getOrderId()); props.put("userId", order.getUserId()); props.put("amount", order.getAmount()); props.put("status", order.getStatus()); return props; // 返回 null 或空 Map 时,该事件会被丢弃 } } ``` **重要约束:** - `TraceSampler` 必须是**线程安全**的,框架会对实例进行缓存 - 若 `process()` 返回 `null` 或空 Map,该事件会被自动丢弃 - 泛型 `T` 的匹配规则: - `T = Object`:取参数列表第一个对象 - `T = Object[]`:将整个参数列表打包为数组 - `T = 具体子类`:遍历参数列表,取第一个匹配类型的参数 - 若参数列表为空或找不到期望类型,抛出 `IllegalArgumentException` - **若采样来源是方法返回值,则 `T` 只能为 `Object`** --- ### 3. 定义收集器(Collector) 实现 `TraceCollector`,对样本进行清洗并指定转储目标: ```java @Component public class OrderCollector extends TraceCollector { public OrderCollector(IEventStorage storage) { super(storage); // 例如:注入一个写入数据库的 IEventStorage 实现 } @Override public void collect(TraceEvent event) { // 清洗逻辑:过滤敏感字段、格式化、补充上下文等 String cleaned = doClean(event); storage.storage(cleaned); // 转储至目标存储 } @Override public boolean isSupport(TraceEvent event) { // 按 group 路由,只处理订单相关事件 return "order".equals(event.getGroup()); } } ``` **设计说明:** - 支持**链式处理**:同一个 `TraceEvent` 可被多个 `TraceCollector` 依次处理 - `isSupport()` 用于按 `group` 做路由匹配,实现分组收集 --- ### 4. 在业务方法上埋点 使用 `@TraceSource` 声明拦截点: ```java @Service public class OrderService { @TraceSource( group = "order", type = "create", description = "订单创建", sampler = OrderSampler.class // 指定采样器 ) public OrderDTO createOrder(CreateOrderRequest request) { // 业务逻辑... return orderDTO; } } ``` **多采样点支持:** ```java @MultiTraceSources({ @TraceSource(group = "order", type = "create", sampler = OrderSampler.class), @TraceSource(group = "audit", type = "order_create", sampler = AuditSampler.class) }) public OrderDTO createOrder(CreateOrderRequest request) { // 业务逻辑... } ``` > **AOP 使用前提**:目标方法必须满足 Spring AOP 的拦截条件(基于接口代理或 CGLIB 类增强)。建议业务层保持良好的接口设计规范。 --- ### 5. 启动配置 **采样端(Client)** — 在启动类添加: ```java @EnableZTraceClient @SpringBootApplication public class SamplerApplication { public static void main(String[] args) { SpringApplication.run(SamplerApplication.class, args); } } ``` **收集端(Server)** — 在启动类添加: ```java @EnableZTraceServer @SpringBootApplication public class CollectorApplication { public static void main(String[] args) { SpringApplication.run(CollectorApplication.class, args); } } ``` > 同一实例可同时启用 Client + Server:同时标注 `@EnableZTraceClient` 和 `@EnableZTraceServer`。 --- ## 配置项参考 ### 采样端(Client) - | 属性 | 类型 | 说明 | 默认值 | |:---|:---|:---|:---| | `ztrace.sampler.default.core.thread` | Integer | 异步采样线程池核心线程数 | `20` | | `ztrace.sampler.default.max.thread` | Integer | 异步采样线程池最大线程数 | `40` | | `ztrace.sampler.default.max.queue` | Integer | 异步采样线程池队列容量 | `1000` | | `ztrace.sampler.default.thread.keepalive` | Long | 非核心线程空闲存活时间(ms) | `1000` | | ztrace.sampler.default.reject | String | 异步采样线程池的拒绝策略类型。主要有:
**Abort** :rejected tasks that throws a RejectedExecutionException
**Discard** :rejected tasks that silently discards the rejected task
**CallerRuns** :runs the rejected task directly in the calling thread
**CallerBlock** :blocks the caller until the executor has room in its queue, or a timeout occurs with default timeout 5s
| CallerRuns | | `ztrace.sampler.group.skip-pattern` | String | 按 `group` 过滤的正则表达式,`null` 表示不过滤 | `null` | | `ztrace.sampler.type.skip-pattern` | String | 按 `type` 过滤的正则表达式,`null` 表示不过滤 | `null` | | `ztrace.client.meta.send.type` | String | 采样数据转储方式:`MQ` / `HTTP` / `REDIS` | `MQ` | | `ztrace.client.meta.send.uri` | String | `send.type=HTTP` 时,收集端接收地址 | `http://localhost:8080/ztrace/collect` | | `ztrace.client.meta.send.debug` | Boolean | `send.type=HTTP` 时,是否打印请求日志 | `true` | | `ztrace.client.meta.redis.topic` | String | `send.type=REDIS` 时,Redis 频道名 | `ZTrace` | ### 收集端(Server) | 属性 | 类型 | 说明 | 默认值 | |:---|:---|:---|:---| | `ztrace.server.meta.receive.type` | String | 样本消费方式:`MQ` / `HTTP` / `REDIS` | `MQ` | | `ztrace.server.meta.redis.topic` | String | `receive.type=REDIS` 时,Redis 频道名 | `ZTrace` | > **HTTP 模式**:当 `receive.type=HTTP` 时,框架会自动注册端点 `/ztrace/collect`,无需手动编写 Controller。 --- ## 设计特性 ### 1. 非侵入式埋点 基于 Spring AOP 实现,通过注解声明在方法签名上,**不修改业务代码逻辑**。支持接口动态代理和 CGLIB 类增强。 ### 2. 异常隔离 采样过程默认全局异常捕获,**任何框架异常都不会外抛**,确保业务功能不受影响。异常信息通过日志输出,开发者需关注日志排查问题。 ### 3. 采样效率控制 - **采样率**:支持间隙性抽样,默认全量采集 - **同步/异步采集**:异步模式基于线程池,支持核心线程数、队列容量等参数调优 - **过滤正则**:支持按 `group` 和 `type` 做正则过滤,减少无效采集 ### 4. 灵活部署 - Sampler 与 Collector 可**同实例集成**,也可**独立服务部署** - 支持多种存储介质,适应不同架构场景 --- ## 存储介质说明 | 模式 | 适用场景 | 说明 | |:---|:---|:---| | **MQ**(默认) | 高并发(高流量)生产环境 | 基于 Spring Cloud Stream,默认 Kafka。Sampler 写入 Topic,Collector 消费 Topic | | **HTTP** | 低并发(低流量)生产环境 | Sampler 直接 HTTP POST 到 Collector 端点。适合无 MQ 或者Redis等基础中间件设施的场景, 但对于Collector而言要考虑请求负载冲击自身业务的可能性。 | | **Redis** | 较高并发(较高流量)生产环境 | 基于 Redis List 实现(`LPUSH`/`BRPOP`),适用于已有 Redis 且消息消费不严格的场景 | | **Console / 文件** | ⚠️ **仅限本地测试** | 打印到控制台或写入本地日志文件,**严禁用于生产环境** | --- ## 注意事项 1. **线程安全**:`TraceSampler` 实例会被框架缓存复用,实现时必须保证线程安全 2. **参数匹配**:`TraceSampler` 的泛型 `T` 决定参数注入规则,若采样来源为方法返回值,则 `T` 只能为 `Object` 3. **事件丢弃**:`TraceSampler.process()` 返回 `null` 或空 Map 时,该事件会被静默丢弃 4. **AOP 前提**:`@TraceSource` 依赖 Spring AOP,目标 Bean 必须能被代理(建议基于接口编程)