核心是将埋点逻辑抽取为独立切面,通过注解或表达式精准切点,按场景选用前置/环绕/返回通知,动态注入参数并封装上报,全程try-catch隔离且支持采样与动态开关。

核心思路是把埋点逻辑从函数内部抽出来,放到独立的“切面”里,通过运行时或编译期织入,自动附加到目标方法前后——业务代码完全不用改,也不感知。
明确切点:用注解或表达式精准圈定要监控的方法
避免全量扫描带来的性能损耗和误埋。推荐两种主流方式:
-
注解驱动:自定义如
@TrackEvent("page_view"),加在需要埋点的方法上;切面只拦截带该注解的方法,清晰可控 -
表达式匹配:例如 Spring AOP 的
execution(* com.app.ui.*.onCreate(..)),批量覆盖 Activity 生命周期方法;Android 或 iOS 可用 Method Swizzling / AspectJ 按类名、方法名通配匹配
选择合适的通知类型:按埋点场景决定执行时机
不是所有埋点都适合“环绕”——选错通知类型容易漏数据或重复上报:
- 前置通知(Before):适合页面曝光、按钮点击这类“动作发起即上报”的场景,比如用户点击按钮瞬间记录事件名和上下文
- 环绕通知(Around):必须用在需计算耗时、捕获返回值或异常的场景,例如接口请求埋点,可记录开始时间、响应结果、错误码
- 返回/异常通知(AfterReturning / AfterThrowing):适合只关心成功路径或失败归因的指标,比如订单提交成功后打点,或网络异常时自动附加上报堆栈
封装通用埋点能力:让切面真正“无侵入”
切面本身不能硬编码业务字段,否则又变相耦合。应支持动态参数注入:
- 从注解中提取元数据,如
@TrackEvent(value="search", category="user_action"),自动组装为标准日志对象 - 通过
JoinPoint获取方法名、参数值(注意脱敏)、类信息,补全上下文(如当前页面、用户ID等可通过 ThreadLocal 或 Context 拿到) - 统一走埋点 SDK 上报通道,不直接调用网络或数据库,保证低侵入性和可替换性
验证与隔离:确保不影响主流程稳定性
切面是横切逻辑,一旦出错可能拖垮整个方法。务必做到:
- 所有埋点逻辑包裹
try-catch,异常静默处理,绝不抛出或阻塞原方法执行 - 设置采样率(如 10% 用户开启全量埋点),避免线上日志爆炸
- 提供开关配置(如配置中心下发),支持运行时一键关闭某类切面,便于故障排查










