@dieugene/telemetry-notifier
v0.1.5
Published
Универсальный модуль для отправки уведомлений о критических ошибках, статистике и событиях в Telegram-бот.
Readme
@dieugene/telemetry-notifier
Универсальный модуль для отправки уведомлений о критических ошибках, статистике и событиях в Telegram-бот.
Особенности
- 🔄 Синглтон через
globalThisдля переиспользования в разных сервисах - 📡 Легковесный HTTP-клиент без зависимости от telegraf
- 💾 KV-хранилище для детальной информации с inline-кнопками
- 🔄 Автоматические ретраи с экспоненциальным backoff
- 📊 Отслеживание промежуточных данных сессии через
track() - 🎯 Поддержка разных типов уведомлений: fatal, error, warn, info, stats
- ✉️ Email-уведомления с простой сериализацией объекта (SMTP,
nodemailer)
Установка
npm install @dieugene/telemetry-notifierКонфигурация
Переменные окружения
TELEMETRY_BOT_TOKEN=bot_token_here
TELEMETRY_CHAT_ID=chat_id_here
TELEMETRY_DOMAIN=TELEMETRY_NOTIFIER
TELEMETRY_ENV=production
TELEMETRY_SERVICE=my-service
TELEMETRY_DELAY_MS=1000
TELEMETRY_MAX_RETRIES=3
# Email (опционально)
[email protected]
TELEMETRY_EMAIL_PASSWORD=secret
# Опциональные переопределения SMTP
[email protected]
TELEMETRY_EMAIL_HOST=smtp.mail.ru
TELEMETRY_EMAIL_PORT=465
TELEMETRY_EMAIL_FROM="NodeMailer <[email protected]>"Использование
Базовое использование
import { TelemetryNotifier } from '@dieugene/telemetry-notifier';
const notifier = TelemetryNotifier.getInstance({
botToken: process.env.TELEMETRY_BOT_TOKEN,
chatId: process.env.TELEMETRY_CHAT_ID,
service: 'my-service',
env: 'production'
});
// Критическая ошибка
try {
// ваш код
} catch (error) {
await notifier.fatal(error, {
title: 'Database connection failed',
sessionId: 'session_123'
});
}
// Обычная ошибка
await notifier.error(new Error('Something went wrong'), {
title: 'API Error',
context: { userId: '123', endpoint: '/api/users' }
});
// Предупреждение
await notifier.warn('High memory usage detected', {
title: 'Performance Warning'
});
// Информация
await notifier.info('Service started successfully', {
title: 'Startup Complete'
});
// Статистика
await notifier.stats('Daily report completed', {
title: 'Daily Statistics',
summary: 'Processed 1000 items in 2 minutes'
});
// Отправка email с данными + инфо-сообщение в Telegram
await notifier.email({
subject: 'User data report',
data: { user: { id: '123' }, billing: { ... } },
// to: '[email protected]' // опционально; если не указать, возьмётся из TELEMETRY_EMAIL_TO
});Отслеживание сессии
const notifier = TelemetryNotifier.getInstance();
// Отслеживание промежуточных данных
notifier.track('Starting user authentication');
notifier.track('Database connection established');
notifier.track('Processing user data');
try {
// ваша логика
} catch (error) {
// Все отслеженные данные попадут в детали уведомления
await notifier.fatal(error, {
title: 'Processing failed',
sessionId: 'session_123'
});
}
// Очистка отслеженных данных (опционально)
notifier.clearTrackedData();Интеграция с SessionTracker
// В вашем SessionTracker
import { TelemetryNotifier } from '@dieugene/telemetry-notifier';
class SessionTracker {
async record_error(stage_name, error, fatal = false) {
// существующая логика...
if (fatal) {
const notifier = TelemetryNotifier.getInstance();
await notifier.fatal(error, {
title: `Fatal error in ${stage_name}`,
sessionId: this.session_id,
context: { stage: stage_name }
});
}
}
async finalize_session() {
// существующая логика...
const notifier = TelemetryNotifier.getInstance();
await notifier.notify_session_summary(session, {
title: 'Session completed'
});
}
}Обработка callback-кнопок
Для работы кнопки "Подробнее" нужно обработать callback_query в вашем боте:
import { TelemetryNotifier, CallbackDataBuilder } from '@dieugene/telemetry-notifier';
const callbackBuilder = new CallbackDataBuilder();
const notifier = TelemetryNotifier.getInstance();
bot.on('callback_query', async (ctx) => {
const callbackData = ctx.callbackQuery.data;
if (callbackBuilder.isValidCallback(callbackData)) {
const parsed = callbackBuilder.parseCallback(callbackData);
if (parsed.action === 'details') {
// Получить детали из репозитория (когда реализован)
const record = await notifier.repo.get(parsed.recordId);
const detailedMessage = notifier.formatter.formatDetails(record);
const backKeyboard = notifier.formatter.buildBackKeyboard(parsed.recordId);
await ctx.editMessageText(detailedMessage, {
parse_mode: 'HTML',
reply_markup: { inline_keyboard: backKeyboard }
});
}
if (parsed.action === 'back') {
const record = await notifier.repo.get(parsed.recordId);
const originalMessage = notifier.formatter.formatMessage(record);
const detailsKeyboard = notifier.formatter.buildInlineKeyboard(parsed.recordId);
await ctx.editMessageText(originalMessage, {
parse_mode: 'HTML',
reply_markup: { inline_keyboard: detailsKeyboard }
});
}
await ctx.answerCbQuery();
}
});API Reference
TelemetryNotifier
Статические методы
getInstance(config?)- Получить синглтон-экземпляр
Методы экземпляра
track(message)- Отследить промежуточное событиеgetTrackedData()- Получить все отслеженные событияclearTrackedData()- Очистить отслеженные событияfatal(error, context?)- Критическая ошибкаerror(error, context?)- Обычная ошибкаwarn(message, context?)- Предупреждениеinfo(message, context?)- Информацияstats(summary, context?)- Статистикаnotify_session_summary(session, context?)- Сводка сессииemail({ subject, data, to? })- Отправка email (SMTP) и публикация info-сообщения в Telegram
Параметры context
title- Заголовок уведомленияsummary- Краткое описаниеsessionId- ID сессииchatId- Переопределить chat IDcontext- Дополнительные данные
Ограничения
- EmailAdapter требует настроенных SMTP-переменных окружения; при их отсутствии вызов не приводит к отправке письма
- Требуется ручная обработка callback_query для кнопок "Подробнее"
Лицензия
MIT
