异常告警模块与错误处理模块集成,当异常发生时自动触发告警通知。模块提供统一的告警信息模型 AlarmInfo、告警级别 AlarmLevel 以及可扩展的告警处理器接口 ErrorAlarmHandler,支持注册多个处理器同时发送钉钉、企微、邮件、日志等多种告警。

仓库坐标

告警模块 common-alarm 通过 error-spring-boot-starter 传递引入,引入错误处理模块即可使用:

Maven

<dependency>
    <groupId>com.luamas.thinkbridge</groupId>
    <artifactId>error-spring-boot-starter</artifactId>
</dependency>

Gradle

implementation("com.luamas.thinkbridge:error-spring-boot-starter")

核心接口

ErrorAlarmHandler

实现 com.luamas.thinkbridge.common.alarm.ErrorAlarmHandler 接口,自定义告警处理逻辑:

public interface ErrorAlarmHandler {

    /**
     * 处理告警信息
     *
     * @param alarmInfo 告警信息
     * @return 处理成功返回 true,处理失败返回 false
     */
    boolean handle(AlarmInfo<?> alarmInfo);
}

自定义处理器只需实现该接口并注册为 Spring Bean,框架会自动收集所有 ErrorAlarmHandler 并在异常发生时依次调用:

@Component
public class MyAlarmHandler implements ErrorAlarmHandler {
    @Override
    public boolean handle(AlarmInfo<?> alarmInfo) {
        Throwable exception = alarmInfo.getException();
        Object response = alarmInfo.getObj();
        AlarmLevel level = alarmInfo.getLevel();
        String type = alarmInfo.getType();
        // 自定义告警逻辑,如发送钉钉/企微/邮件通知
        return true;
    }
}
可以注册多个 ErrorAlarmHandler,如同时发送钉钉和邮件告警。返回 true 表示告警处理成功,返回 false 表示处理失败,框架会记录警告日志。

AlarmInfo

com.luamas.thinkbridge.common.alarm.AlarmInfo<T> 是告警信息模型,泛型 T 表示关联的业务对象类型(通常为错误响应体)。

字段说明

字段

类型

说明

exception

Throwable

触发告警的异常对象,可能为 null

obj

T

关联的业务对象,通常为错误响应体 ResponseVo

level

AlarmLevel

告警级别(WARN / ERROR / FATAL)

type

String

告警类型,见下方类型常量

extend

Map<String, Object>

扩展数据,默认初始化为空 HashMap

类型常量

AlarmInfo 内置以下告警类型常量:

常量

值

说明

TYPE_CLIENT_HTTP

CLIENT_HTTP

客户端 HTTP 请求告警(如 Feign 调用)

TYPE_ACCESS_HTTP

ACCESS_HTTP

访问 HTTP 请求告警(服务端入口)

TYPE_MESSAGING_CONSUMER

MESSAGING_CONSUMER

消息消费者告警

TYPE_MESSAGING_PRODUCER

MESSAGING_PRODUCER

消息生产者告警

扩展数据

extend 字段用于存储自定义业务数据,默认已初始化为空 HashMap,可直接使用:

AlarmInfo<?> alarmInfo = new AlarmInfo<>(exception, response, AlarmLevel.ERROR, AlarmInfo.TYPE_ACCESS_HTTP);

// 逐个添加扩展字段
alarmInfo.addExtend("userId", "1001");
alarmInfo.addExtend("tenantId", "thinkbridge");

// 一次性替换整个扩展字段(传入 null 会自动初始化为空 Map)
Map<String, Object> extend = new HashMap<>();
extend.put("orderId", "ORD-2026-001");
alarmInfo.setExtend(extend);

AlarmLevel 枚举

com.luamas.thinkbridge.common.alarm.AlarmLevel

枚举值

数值

说明

WARN

0

警告,已知业务异常触发

ERROR

1

普通错误,未知异常触发

FATAL

2

致命错误

ErrorAlarmManager

com.luamas.thinkbridge.common.alarm.ErrorAlarmManager 是告警分发管理器,负责将告警信息分发给所有注册的处理器。错误处理模块内部直接遍历 ErrorAlarmHandler 列表进行分发,如需在非异常场景下手动触发告警,可使用 ErrorAlarmManager:

@Component
@RequiredArgsConstructor
public class MyService {
    private final List<ErrorAlarmHandler> errorAlarmHandlers;

    public void doSomething() {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 手动构建告警信息并触发告警
            ErrorAlarmManager manager = new ErrorAlarmManager(errorAlarmHandlers);
            AlarmInfo<?> alarmInfo = new AlarmInfo<>(e, null, AlarmLevel.ERROR, AlarmInfo.TYPE_CLIENT_HTTP);
            manager.handle(alarmInfo);
            throw e;
        }
    }
}
ErrorAlarmManager.handle() 会依次调用所有处理器,单个处理器抛出异常不会影响其他处理器的执行,处理器返回 false 会记录警告日志。

告警触发机制

告警由错误处理模块的 ErrorExceptionManager 自动触发,流程如下:

  1. 错误处理模块在处理异常时,自动创建 AlarmInfo

  2. 如果异常被某个 ErrorExceptionHandler 成功处理(匹配到对应处理器),告警级别为 WARN

  3. 如果异常未被任何 ErrorExceptionHandler 处理(走默认处理),告警级别为 ERROR

  4. 如果异常实现了 ThinkBridgeException 接口,且 isAlarmEnabled() 返回 false,则跳过告警

  5. 遍历所有 ErrorAlarmHandler,调用 handle() 方法

  6. 如果 handle() 返回 false,记录警告日志

关闭告警

通过 BusinessException.of(…​).noAlarm() 可关闭单个异常的告警:

// 该异常不会触发告警
throw BusinessException.of(ResultCode.CAPTCHA_ERROR, userId).noAlarm();

自定义异常继承 AbstractException 后,默认 alarmEnabled = true,可通过重写 isAlarmEnabled() 或在构造时设置 alarmEnabled = false 来关闭告警。详见错误处理的「异常使用」章节。

处理器示例

打印告警

最简单的处理器,将告警信息序列化后打印:

@Component
@Slf4j
public class PrintErrorAlarmHandler implements ErrorAlarmHandler {
    private final ObjectMapper objectMapper = JsonMapper.builder().build();

    @Override
    public boolean handle(AlarmInfo<?> alarmInfo) {
        log.info("触发告警: {}", objectMapper.writeValueAsString(alarmInfo));
        return true;
    }
}

日志收集告警

将告警信息通过日志系统收集(可配合 logback 收集到 Kafka/RabbitMQ):

@Component
@Slf4j
@RequiredArgsConstructor
public class LogBackErrorAlarmHandler implements ErrorAlarmHandler {
    private final ThinkBridgeLogProperties properties;
    private final ObjectMapper objectMapper = JsonMapper.builder().build();

    @Override
    public boolean handle(AlarmInfo<?> alarmInfo) {
        Map<String, Object> map = new HashMap<>(alarmInfo.getExtend());
        map.put("obj", alarmInfo.getObj());
        map.put("level", alarmInfo.getLevel());
        map.put("type", alarmInfo.getType());
        map.put("traceId", MDC.get(properties.getTraceIdTag()));
        log.error(objectMapper.writeValueAsString(map));
        return true;
    }
}

邮件告警

根据告警级别发送邮件通知,ERROR 级别才发送:

@Component
@Slf4j
@RequiredArgsConstructor
public class EmailAlarmHandler implements ErrorAlarmHandler {
    private final EmailService emailService;
    private final ApplicationContext applicationContext;

    @Override
    public boolean handle(AlarmInfo<?> alarmInfo) {
        if (alarmInfo == null || alarmInfo.getLevel() != AlarmLevel.ERROR) {
            return true;
        }
        String subject = "[" + alarmInfo.getLevel() + "][" + alarmInfo.getType() + "]"
                + applicationContext.getId();
        String content = buildContent(alarmInfo);
        try {
            emailService.sendHtmlEmail(new String[]{"admin@example.com"}, null, subject, content);
        } catch (Exception e) {
            log.warn("邮件告警发送失败", e);
            return false;
        }
        return true;
    }

    private String buildContent(AlarmInfo<?> alarmInfo) {
        // 构建邮件内容
        return "<h3>告警信息</h3>" + alarmInfo.getException().getMessage();
    }
}
完整示例可参考 sample/integration/integration-demo 模块下的 alarm 包,通过 alarm profile 激活。