SpringBoot + 规则执行日志 + 调试回放:线上规则为何不生效?一键复现执行过程

引言

在复杂的业务系统中,规则引擎已经成为处理业务逻辑的重要工具。但你是否遇到过这样的困扰:线上规则突然不生效了,排查起来却无从下手?规则执行结果不符合预期,但又不知道问题出在哪里?

今天我们就来聊聊如何通过规则执行日志追踪调试回放技术,让规则执行过程变得透明可控,真正做到"一键复现"线上问题。

问题背景

在实际开发中,规则引擎的使用场景越来越广泛:

  • 电商系统的促销规则
  • 金融风控的评估规则
  • 用户权限的控制规则
  • 订单处理的业务规则

但随之而来的挑战是:

  1. 黑盒问题:规则执行过程不透明,难以追踪
  2. 调试困难:线上问题无法重现,只能靠猜
  3. 性能监控:规则执行耗时无法统计
  4. 版本管理:规则变更历史无法追溯

核心解决方案

我们采用的技术栈:

  • SpringBoot 2.7 + Easy Rules 作为规则引擎基础
  • Redis 作为执行轨迹存储
  • 自定义监听器 捕获执行过程
  • traceId机制 实现执行链路追踪

1. 规则执行日志记录

核心思路是通过监听器机制,捕获规则执行的每个关键环节:

// 规则执行监听器
public class ExecutionLoggingRuleListener implements RuleListener {
    
    @Override
    public boolean beforeEvaluate(Rule rule, Facts facts) {
        // 记录执行前的上下文快照
        contextSnapshot.clear();
        for (String name : facts.names()) {
            contextSnapshot.put(name, facts.get(name));
        }
        return true;
    }
    
    @Override
    public void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult) {
        // 记录条件评估结果
        logger.recordStep(
            traceId,
            rule.getName(),
            "CONDITION_EVALUATION",
            contextSnapshot,
            evaluationResult,
            null,
            getCurrentContext(facts)
        );
    }
    
    @Override
    public void onSuccess(Rule rule, Facts facts) {
        // 记录动作执行结果
        logger.recordStep(
            traceId,
            rule.getName(),
            "ACTION_EXECUTION",
            contextSnapshot,
            null,
            "SUCCESS",
            getCurrentContext(facts)
        );
    }
}

2. 执行轨迹管理

每个规则执行都会生成唯一的traceId,并记录完整的执行信息:

public class RuleExecutionRecord {
    private String traceId;           // 执行轨迹ID
    private String ruleId;            // 规则ID
    private String ruleName;          // 规则名称
    private Map<String, Object> facts; // 执行时的上下文
    private List<ExecutionStep> steps; // 执行步骤列表
    private LocalDateTime startTime;  // 开始时间
    private LocalDateTime endTime;    // 结束时间
    private Long duration;            // 执行耗时
    private String status;            // 执行状态
}

3. 调试回放功能

通过traceId可以一键重放历史执行过程:

@PostMapping("/replay/{traceId}")
public ReplayResult replayExecution(@PathVariable String traceId) {
    RuleExecutionRecord record = executionLogger.getExecutionRecord(traceId);
    
    return ReplayResult.builder()
        .traceId(traceId)
        .steps(record.getSteps())
        .duration(record.getDuration())
        .status(record.getStatus())
        .conditionEvaluations(countConditionSteps(record.getSteps()))
        .actionExecutions(countActionSteps(record.getSteps()))
        .build();
}

实现细节

1. 数据存储设计

使用Redis存储执行轨迹,支持高效查询:

// 轨迹存储
String key = "rule:trace:" + traceId;
redisTemplate.opsForValue().set(key, record, 24, TimeUnit.HOURS);

// 规则索引
String indexKey = "rule:trace:index:" + ruleId;
redisTemplate.opsForSet().add(indexKey, traceId);

2. 上下文快照机制

在每个执行步骤前后都记录完整的上下文状态:

public class ExecutionStep {
    private Map<String, Object> contextBefore; // 执行前上下文
    private Map<String, Object> contextAfter;  // 执行后上下文
    private Object conditionResult;   // 条件评估结果
    private String actionResult;      // 动作执行结果
}

3. 性能优化考虑

  • 异步记录日志,避免影响主流程性能
  • 合理设置过期时间,避免存储膨胀
  • 支持采样记录,控制存储成本

使用示例

1. 执行规则并记录

curl -X POST http://localhost:8080/api/rule-debug/execute \
  -H "Content-Type: application/json" \
  -d '{
    "ruleName": "用户等级规则",
    "ruleDescription": "根据用户积分判断用户等级",
    "condition": "score >= 1000",
    "action": "level = \"VIP\"",
    "facts": {
      "score": 1500
    }
  }'

2. 查看执行记录

# 获取执行记录详情
curl http://localhost:8080/api/rule-debug/record/TRACE_1234567890_abcd1234

# 获取规则执行历史
curl "http://localhost:8080/api/rule-debug/records/rule/user_level_rule?limit=10"

3. 重放执行过程

# 重放执行过程
curl -X POST http://localhost:8080/api/rule-debug/replay/TRACE_1234567890_abcd1234

# 分析上下文变化
curl http://localhost:8080/api/rule-debug/context-changes/TRACE_1234567890_abcd1234

实际应用场景

1. 线上问题排查

当用户反馈"为什么我的积分达到1500了还不是VIP?"时:

  1. 通过用户ID找到相关的执行记录
  2. 查看traceId对应的执行过程
  3. 分析哪个步骤出了问题
  4. 快速定位是规则条件还是动作执行的问题

2. 规则调试优化

// 获取规则执行统计
ReplayResult result = replayExecution(traceId);
System.out.println("条件评估次数: " + result.getConditionEvaluations());
System.out.println("动作执行次数: " + result.getActionExecutions());
System.out.println("执行耗时: " + result.getDuration() + "ms");

3. 性能监控告警

// 监控规则执行性能
if (result.getDuration() > 1000) {
    // 发送告警:规则执行超时
    alertService.sendAlert("规则执行超时", traceId);
}

最佳实践建议

1. traceId生成策略

private String generateTraceId() {
    return "TRACE_" + System.currentTimeMillis() + "_" + 
           UUID.randomUUID().toString().substring(0, 8);
}

2. 日志级别控制

logging:
  level:
    com.example.rule.debug: DEBUG
    org.jeasy.rules: INFO

3. 存储策略

  • 开发环境:保留所有执行记录
  • 测试环境:保留1天执行记录
  • 生产环境:保留24小时执行记录

4. 安全考虑

  • 敏感信息脱敏处理
  • 访问权限控制
  • 操作审计日志

总结

通过规则执行日志追踪和调试回放技术,我们实现了:

执行过程透明化:每个步骤都有详细记录
问题定位快速化:一键复现历史执行
性能监控可视化:执行耗时统计分析
调试体验友好化:类似断点调试的体验

这套方案不仅解决了规则引擎的调试难题,更为复杂的业务规则系统提供了可靠的运维保障。

核心价值:让规则执行从"黑盒"变成"白盒",让线上问题排查从"猜谜"变成"证据确凿"。


如果你觉得这篇文章对你有帮助,欢迎关注"服务端技术精选",获取更多实用的技术干货!


标题:SpringBoot + 规则执行日志 + 调试回放:线上规则为何不生效?一键复现执行过程
作者:jiangyi
地址:http://jiangyi.space/articles/2026/02/19/1771137886923.html
公众号:服务端技术精选
    评论
    0 评论
avatar

取消