@nest-packages/nestjs-alert-module
v0.0.1
Published
A pluggable alert module for NestJS with support for multiple channels (Feishu, Sentry, etc.)
Downloads
6
Maintainers
Readme
NestJS Alert Module
一个功能强大、插件化、可扩展的 NestJS 告警模块,支持多种告警渠道(飞书、Sentry、Logger 等)。
✨ 特性
- 🔌 插件化架构 - 轻松扩展新的告警渠道
- 🎯 多渠道支持 - 飞书(个人/群/Webhook)、Sentry、Logger
- 🛡️ 类型安全 - 完整的 TypeScript 类型定义
- 🚀 开箱即用 - 简单的配置即可快速使用
- 🎨 装饰器支持 -
@Alert()装饰器自动捕获异常 - 🔄 智能重试 - 自动重试失败的告警
- 🚦 限流控制 - 防止告警风暴
- 🔁 去重机制 - 避免重复告警
- 💉 依赖注入 - 完全使用 NestJS 依赖注入
- 🧪 易于测试 - 良好的可测试性
📦 安装
npm install @libs/nestjs-alert-module
# 或
yarn add @libs/nestjs-alert-module
# 或
pnpm add @libs/nestjs-alert-module依赖
npm install @nestjs/common @nestjs/core @nestjs/axios rxjs fast-safe-stringify🚀 快速开始
1. 导入模块
import { Module } from '@nestjs/common';
import { AlertModule, AlertChannelType } from '@libs/nestjs-alert-module';
@Module({
imports: [
// 同步配置
AlertModule.forRoot({
isGlobal: true,
defaultChannels: [
{
type: AlertChannelType.FEISHU_WEBHOOK,
config: {
webhookUrl: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxx',
},
},
],
rateLimit: {
enabled: true,
maxRequests: 10,
windowMs: 60000, // 1分钟
},
deduplication: {
enabled: true,
ttl: 300, // 5分钟
},
retry: {
enabled: true,
maxAttempts: 3,
delay: 1000,
},
}),
// 或异步配置
AlertModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
isGlobal: true,
defaultChannels: [
{
type: AlertChannelType.FEISHU_WEBHOOK,
config: {
webhookUrl: configService.get('FEISHU_WEBHOOK_URL'),
},
},
],
feishu: {
appId: configService.get('FEISHU_APP_ID'),
appSecret: configService.get('FEISHU_APP_SECRET'),
},
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}2. 使用 AlertService
import { Injectable } from '@nestjs/common';
import { AlertService, AlertLevel } from '@libs/nestjs-alert-module';
@Injectable()
export class UserService {
constructor(private readonly alertService: AlertService) {}
async createUser(data: any) {
try {
const user = await this.userRepository.save(data);
// 发送成功告警
await this.alertService.info('用户创建成功', {
userId: user.id,
username: user.username,
});
return user;
} catch (error) {
// 发送错误告警
await this.alertService.error('用户创建失败', error, {
inputData: data,
});
throw error;
}
}
}3. 使用装饰器
import { Injectable } from '@nestjs/common';
import { Alert, AlertLevel, AlertChannelType } from '@libs/nestjs-alert-module';
@Injectable()
export class PaymentService {
@Alert({
title: '支付处理',
level: AlertLevel.ERROR,
channels: [AlertChannelType.FEISHU_WEBHOOK, AlertChannelType.SENTRY],
onlyOnError: true, // 只在异常时发送告警
})
async processPayment(orderId: string, amount: number) {
// 如果方法抛出异常,会自动发送告警
return await this.paymentGateway.charge(orderId, amount);
}
}📖 完整示例
发送到多个渠道
await this.alertService.send({
level: AlertLevel.CRITICAL,
title: '系统严重错误',
content: {
service: 'payment-service',
errorCode: 'PAYMENT_001',
message: '支付网关连接失败',
},
channels: [
{
type: AlertChannelType.FEISHU_WEBHOOK,
config: {
webhookUrl: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxx',
},
},
{
type: AlertChannelType.FEISHU_USER,
config: {
userId: 'ou_xxx', // 飞书用户 Open ID
},
},
{
type: AlertChannelType.FEISHU_GROUP,
config: {
chatId: 'oc_xxx', // 飞书群 ID
},
},
{
type: AlertChannelType.SENTRY,
config: {},
},
{
type: AlertChannelType.LOGGER,
config: {},
},
],
metadata: {
traceId: 'trace-123456',
environment: 'production',
},
tags: ['payment', 'critical'],
});📚 API 文档
AlertService
send(message: IAlertMessage): Promise<AlertResult[]>
发送告警到指定渠道。
error(title: string, error: Error | string, metadata?: Record<string, any>): Promise<AlertResult[]>
发送错误告警。
warning(title: string, content: string | Record<string, any>, metadata?: Record<string, any>): Promise<AlertResult[]>
发送警告告警。
info(title: string, content: string | Record<string, any>, metadata?: Record<string, any>): Promise<AlertResult[]>
发送信息告警。
critical(title: string, content: string | Record<string, any>, metadata?: Record<string, any>): Promise<AlertResult[]>
发送严重告警。
告警级别
enum AlertLevel {
INFO = 'info',
WARNING = 'warning',
ERROR = 'error',
CRITICAL = 'critical',
}告警渠道类型
enum AlertChannelType {
FEISHU_USER = 'feishu_user', // 飞书个人消息
FEISHU_GROUP = 'feishu_group', // 飞书群消息
FEISHU_WEBHOOK = 'feishu_webhook', // 飞书 Webhook
SENTRY = 'sentry', // Sentry
LOGGER = 'logger', // 日志
EMAIL = 'email', // 邮件(预留)
SMS = 'sms', // 短信(预留)
CUSTOM = 'custom', // 自定义
}🔌 自定义渠道插件
创建自定义渠道
import { Injectable } from '@nestjs/common';
import { IAlertChannel, AlertChannelType, IAlertMessage, AlertResult } from '@libs/nestjs-alert-module';
@Injectable()
export class EmailAlertChannel implements IAlertChannel {
readonly name = 'email';
readonly type = AlertChannelType.EMAIL;
async send(message: IAlertMessage): Promise<AlertResult> {
// 实现邮件发送逻辑
try {
await this.sendEmail(message);
return {
success: true,
channel: this.name,
timestamp: new Date(),
};
} catch (error) {
return {
success: false,
channel: this.name,
error: error.message,
timestamp: new Date(),
};
}
}
async validateConfig(config: any): Promise<boolean> {
return !!config.to && !!config.subject;
}
private async sendEmail(message: IAlertMessage): Promise<void> {
// 邮件发送实现
}
}创建插件
import { Injectable } from '@nestjs/common';
import { IAlertPlugin, IAlertChannel } from '@libs/nestjs-alert-module';
@Injectable()
export class EmailAlertPlugin implements IAlertPlugin {
readonly name = 'email-alert-plugin';
readonly version = '1.0.0';
constructor(private readonly emailChannel: EmailAlertChannel) {}
register(): IAlertChannel {
return this.emailChannel;
}
}注册插件
@Module({
imports: [
AlertModule.forRoot({ /* ... */ }),
],
providers: [
EmailAlertChannel,
EmailAlertPlugin,
],
})
export class AppModule {}⚙️ 配置选项
interface AlertModuleOptions {
/**
* 是否全局模块
*/
isGlobal?: boolean;
/**
* 默认告警渠道
*/
defaultChannels?: AlertChannelTarget[];
/**
* 飞书配置
*/
feishu?: {
appId?: string;
appSecret?: string;
webhooks?: Record<string, string>;
};
/**
* Sentry 配置
*/
sentry?: {
dsn?: string;
environment?: string;
};
/**
* 限流配置
*/
rateLimit?: {
enabled: boolean;
maxRequests: number;
windowMs: number;
};
/**
* 去重配置
*/
deduplication?: {
enabled: boolean;
ttl: number;
};
/**
* 重试配置
*/
retry?: {
enabled: boolean;
maxAttempts: number;
delay: number;
};
}🧪 测试
import { Test } from '@nestjs/testing';
import { AlertService, AlertModule } from '@libs/nestjs-alert-module';
describe('AlertService', () => {
let alertService: AlertService;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [
AlertModule.forRoot({
defaultChannels: [],
}),
],
}).compile();
alertService = module.get<AlertService>(AlertService);
});
it('should send alert', async () => {
const results = await alertService.info('Test Alert', 'Test content');
expect(results).toBeDefined();
});
});📝 最佳实践
- 使用全局模块 - 将 AlertModule 配置为全局模块,避免在每个模块中重复导入
- 合理配置限流 - 根据实际情况配置限流参数,防止告警风暴
- 启用去重 - 开启去重功能,避免短时间内重复发送相同告警
- 分级告警 - 根据错误严重程度使用不同的告警级别
- 添加元数据 - 在告警中添加 traceId、环境等元数据,便于问题追踪
- 使用装饰器 - 对于需要监控的方法,使用
@Alert()装饰器简化代码
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📄 许可证
MIT
🔗 相关链接
📮 联系方式
如有问题或建议,欢迎联系我们。
