Files
ResourceUsageAPI/Services/TelegramNotificationService.cs
Phoenix d6efa9163b Add Telegram bot integration for real-time alert notifications
- Implemented ITelegramNotificationService and TelegramNotificationService for sending alerts via Telegram.
- Updated MonitoringSettings to include Telegram configuration options.
- Enhanced AlertService to send alerts and resolutions through Telegram.
- Added API endpoints for checking Telegram status and sending test alerts.
- Updated README and TELEGRAM_SETUP.md with setup instructions and features.
- Included example configuration in appsettings.telegram.example.json.
2025-08-07 17:30:02 +08:00

207 lines
7.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ResourceMonitorService.Configuration;
using ResourceMonitorService.Models;
using Telegram.Bot;
using Telegram.Bot.Exceptions;
using Telegram.Bot.Types.Enums;
namespace ResourceMonitorService.Services
{
public interface ITelegramNotificationService
{
Task SendAlertAsync(Alert alert);
Task SendAlertResolvedAsync(Alert alert);
Task<bool> IsEnabledAsync();
Task<bool> TestConnectionAsync();
}
public class TelegramNotificationService : ITelegramNotificationService
{
private readonly ILogger<TelegramNotificationService> _logger;
private readonly TelegramSettings _telegramSettings;
private readonly ITelegramBotClient? _botClient;
public TelegramNotificationService(
ILogger<TelegramNotificationService> logger,
IOptions<MonitoringSettings> settings)
{
_logger = logger;
_telegramSettings = settings.Value.Telegram;
if (_telegramSettings.IsEnabled && !string.IsNullOrEmpty(_telegramSettings.BotToken))
{
try
{
_botClient = new TelegramBotClient(_telegramSettings.BotToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to initialize Telegram bot client");
}
}
}
public async Task<bool> IsEnabledAsync()
{
return await Task.FromResult(_telegramSettings.IsEnabled && _botClient != null);
}
public async Task<bool> TestConnectionAsync()
{
if (_botClient == null || !_telegramSettings.IsEnabled)
return false;
try
{
var me = await _botClient.GetMe();
_logger.LogInformation("Telegram bot connected successfully: @{Username}", me.Username);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to connect to Telegram bot");
return false;
}
}
public async Task SendAlertAsync(Alert alert)
{
if (_botClient == null || !_telegramSettings.IsEnabled)
return;
// Check if we should send this type of alert
if ((alert.Level == "Warning" && !_telegramSettings.SendWarningAlerts) ||
(alert.Level == "Critical" && !_telegramSettings.SendCriticalAlerts))
{
return;
}
var message = FormatAlertMessage(alert, _telegramSettings.MessageTemplate);
foreach (var chatId in _telegramSettings.ChatIds)
{
try
{
await _botClient.SendMessage(
chatId: chatId,
text: message,
parseMode: ParseMode.Markdown,
disableNotification: alert.Level == "Warning" // Don't ping for warnings
);
_logger.LogInformation("Telegram alert sent to chat {ChatId}: {AlertLevel} - {Component}",
chatId, alert.Level, alert.Component);
}
catch (ApiRequestException ex)
{
_logger.LogError(ex, "Failed to send Telegram alert to chat {ChatId}: {ErrorCode} - {Description}",
chatId, ex.ErrorCode, ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error sending Telegram alert to chat {ChatId}", chatId);
}
}
}
public async Task SendAlertResolvedAsync(Alert alert)
{
if (_botClient == null || !_telegramSettings.IsEnabled || !_telegramSettings.SendResolutionNotifications)
return;
var message = FormatAlertMessage(alert, _telegramSettings.ResolutionTemplate);
foreach (var chatId in _telegramSettings.ChatIds)
{
try
{
await _botClient.SendMessage(
chatId: chatId,
text: message,
parseMode: ParseMode.Markdown,
disableNotification: true // Don't ping for resolutions
);
_logger.LogInformation("Telegram resolution notification sent to chat {ChatId}: {Component}",
chatId, alert.Component);
}
catch (ApiRequestException ex)
{
_logger.LogError(ex, "Failed to send Telegram resolution to chat {ChatId}: {ErrorCode} - {Description}",
chatId, ex.ErrorCode, ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error sending Telegram resolution to chat {ChatId}", chatId);
}
}
}
private string FormatAlertMessage(Alert alert, string template)
{
var levelIcon = alert.Level switch
{
"Critical" => "🔴",
"Warning" => "⚠️",
_ => "️"
};
var componentIcon = alert.Component switch
{
"CPU" => "🖥️",
"CPUTemp" => "🌡️",
"Memory" => "💾",
"GPU" => "🎮",
"GPUTemp" => "🌡️",
var disk when disk.StartsWith("Disk") => "💽",
var process when process.StartsWith("ProcessMemory") => "⚙️",
_ => "📊"
};
// Replace template placeholders
var message = template
.Replace("{Level}", alert.Level)
.Replace("{Component}", alert.Component)
.Replace("{Message}", EscapeMarkdown(alert.Message))
.Replace("{Timestamp}", alert.Timestamp.ToString("yyyy-MM-dd HH:mm:ss"))
.Replace("{CurrentValue}", alert.CurrentValue.ToString("F1"))
.Replace("{ThresholdValue}", alert.ThresholdValue.ToString("F1"));
if (alert.ResolvedAt.HasValue)
{
message = message.Replace("{ResolvedAt}", alert.ResolvedAt.Value.ToString("yyyy-MM-dd HH:mm:ss"));
}
// Add icons
message = $"{levelIcon} {componentIcon} {message}";
return message;
}
private static string EscapeMarkdown(string text)
{
// Escape special Markdown characters
return text
.Replace("_", "\\_")
.Replace("*", "\\*")
.Replace("[", "\\[")
.Replace("]", "\\]")
.Replace("(", "\\(")
.Replace(")", "\\)")
.Replace("~", "\\~")
.Replace("`", "\\`")
.Replace(">", "\\>")
.Replace("#", "\\#")
.Replace("+", "\\+")
.Replace("-", "\\-")
.Replace("=", "\\=")
.Replace("|", "\\|")
.Replace("{", "\\{")
.Replace("}", "\\}")
.Replace(".", "\\.")
.Replace("!", "\\!");
}
}
}