Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 75 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Stop drowning in alert storms. `@iqai/alert-logger` groups repeated errors using
- **Resolution detection** β€” get a "resolved" message when an error stops occurring
- **Error fingerprinting** β€” same bug from different requests groups automatically (strips IDs, timestamps, UUIDs)
- **Multi-channel routing** β€” route by severity level or custom tags to different channels
- **Adapter architecture** β€” Discord and Console built-in; Sentry, Slack, Telegram as separate packages; or build your own
- **Adapter architecture** β€” Discord, Slack, Telegram, and Console built-in; or build your own
- **NestJS integration** β€” drop-in `@Global()` module with automatic exception filter
- **NextJS integration** β€” `instrumentation.ts` hook with automatic `onRequestError` handler
- **Per-environment config** β€” different suppression thresholds, levels, and ping rules for prod/staging/dev
Expand All @@ -35,16 +35,29 @@ yarn add @iqai/alert-logger
### Standalone (any Node.js project)

```ts
import { AlertLogger, DiscordAdapter } from '@iqai/alert-logger'
import { AlertLogger, DiscordAdapter, SlackAdapter, TelegramAdapter } from '@iqai/alert-logger'

const logger = AlertLogger.init({
adapters: [
new DiscordAdapter({ webhookUrl: process.env.DISCORD_WEBHOOK_URL }),
new DiscordAdapter({
webhookUrl: process.env.DISCORD_WEBHOOK_URL,
channels: { critical: process.env.DISCORD_ONCALL_WEBHOOK },
mentions: { critical: ['<@&oncall-role>'] },
}),
new SlackAdapter({
webhookUrl: process.env.SLACK_WEBHOOK_URL,
mentions: { critical: ['<@U0123ONCALL>'] },
}),
new TelegramAdapter({
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
topics: { critical: 42, warning: 43, info: 44 },
}),
],
serviceName: 'my-service',
})

// Simple error β€” goes to Discord with full context
// Simple error β€” goes to all adapters with full context
logger.error('Payment failed', error)

// With metadata
Expand Down Expand Up @@ -156,17 +169,14 @@ AlertLogger.init({
environments: {
production: {
levels: ['warning', 'critical'],
pings: { critical: ['@here'] },
aggregation: { digestIntervalMs: 5 * 60_000 },
},
staging: {
levels: ['critical'], // only errors, no warnings
pings: {}, // never ping anyone
aggregation: { digestIntervalMs: 15 * 60_000 },
},
development: {
levels: ['critical'],
pings: {},
aggregation: { rampThreshold: 8, digestIntervalMs: 30 * 60_000 },
},
},
Expand All @@ -177,25 +187,54 @@ Every alert is prefixed with an environment badge (`[PROD]`, `[STG]`, `[DEV]`) s

## πŸ“‘ Multi-Channel Routing

Route alerts to different webhooks by severity or tags:
Each adapter owns its routing. Route alerts to different channels/topics by severity or tags:

```ts
AlertLogger.init({
adapters: [new DiscordAdapter({ webhookUrl: DEFAULT_WEBHOOK })],
routing: {
channels: {
info: process.env.DISCORD_INFO_WEBHOOK,
warning: process.env.DISCORD_WARNINGS_WEBHOOK,
critical: process.env.DISCORD_ONCALL_WEBHOOK,
},
tags: {
indexer: process.env.DISCORD_INDEXER_WEBHOOK,
relayer: process.env.DISCORD_RELAYER_WEBHOOK,
},
pings: {
critical: ['@here'],
},
},
adapters: [
// Discord: route by level to different webhook URLs
new DiscordAdapter({
webhookUrl: process.env.DISCORD_DEFAULT_WEBHOOK,
channels: {
critical: process.env.DISCORD_ONCALL_WEBHOOK,
warning: process.env.DISCORD_WARNINGS_WEBHOOK,
},
tags: {
indexer: process.env.DISCORD_INDEXER_WEBHOOK,
},
mentions: {
critical: ['<@&oncall-role>'],
},
}),

// Slack: same pattern with Incoming Webhook URLs
new SlackAdapter({
webhookUrl: process.env.SLACK_DEFAULT_WEBHOOK,
channels: {
critical: process.env.SLACK_ONCALL_WEBHOOK,
},
mentions: {
critical: ['<@U0123ONCALL>'],
},
}),

// Telegram: route by level to forum topics
new TelegramAdapter({
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
topics: {
critical: 42,
warning: 43,
info: 44,
},
tags: {
indexer: 99,
},
mentions: {
critical: ['@oncall_dev'],
},
}),
],
})
```

Expand Down Expand Up @@ -224,8 +263,15 @@ class PagerDutyAdapter implements AlertAdapter {

```ts
AlertLogger.init({
// Required
adapters: [new DiscordAdapter({ webhookUrl: '...' })],
// Required β€” each adapter configures its own routing
adapters: [
new DiscordAdapter({
webhookUrl: '...',
channels: {}, // level β†’ webhook URL
tags: {}, // tag β†’ webhook URL
mentions: {}, // level β†’ mention strings
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The comment level β†’ mention strings is slightly ambiguous. Since the mentions property in DiscordAdapterOptions (and other adapters) is typed as Partial<Record<AlertLevel, string[]>>, it would be clearer to specify that it expects an array of strings, as shown in the examples above.

Suggested change
mentions: {}, // level β†’ mention strings
mentions: {}, // level β†’ string[] (mentions)
References
  1. The AlertLevel type for warnings is 'warning', which is distinct from the API method name .warn().

}),
],

// Identity
serviceName: 'backend', // defaults to hostname
Expand All @@ -238,17 +284,10 @@ AlertLogger.init({
resolutionCooldownMs: 2 * 60_000, // silence before "resolved"
},

// Routing
routing: {
channels: {}, // level β†’ webhook URL
tags: {}, // tag β†’ webhook URL
pings: {}, // level β†’ mention strings
},

// Per-environment overrides
environments: {
production: { levels: ['warning', 'critical'], pings: { critical: ['@here'] } },
staging: { levels: ['critical'], pings: {} },
production: { levels: ['warning', 'critical'] },
staging: { levels: ['critical'] },
development: { levels: ['critical'], aggregation: { rampThreshold: 8 } },
},

Expand All @@ -271,10 +310,10 @@ AlertLogger.init({
| Adapter | Package | Status |
|---------|---------|--------|
| Discord | `@iqai/alert-logger` (built-in) | Available |
| Slack | `@iqai/alert-logger` (built-in) | Available |
| Telegram | `@iqai/alert-logger` (built-in) | Available |
| Console | `@iqai/alert-logger` (built-in) | Available |
| Sentry | `@iqai/alert-logger-sentry` | Planned |
| Slack | `@iqai/alert-logger-slack` | Planned |
| Telegram | `@iqai/alert-logger-telegram` | Planned |

## 🀝 Contributing

Expand Down
Loading