diff --git a/Monithor.api/Alerting.cs b/Monithor.api/Alerting.cs deleted file mode 100644 index cff674c..0000000 --- a/Monithor.api/Alerting.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using Telegram.Bot; -using Telegram.Bot.Types.Enums; -using Telegram.Bot.Types.ReplyMarkups; - -namespace Monithor.api { - public class Alerting { - public class TelegramTarget { - public TelegramTarget(TelegramBotClient client, string chatId, IMonitor monitor, string statusPageRoute, string displayName) { - _client = client; - _chatId = chatId; - Monitor = monitor; - _statusPageRoute = statusPageRoute; - _displayName = displayName; - } - - private readonly TelegramBotClient _client; - private readonly string _chatId; - public readonly IMonitor Monitor; - private readonly string _statusPageRoute; - private readonly string _displayName; - - public async void SendMessage() { - var statusPageBtn = new InlineKeyboardMarkup(InlineKeyboardButton.WithUrl("Open status page", $"https://{_statusPageRoute}")); - var message = GetMessage(Monitor, _displayName); - try { - await _client.SendTextMessageAsync(_chatId, message, ParseMode.Default, replyMarkup: statusPageBtn); - } - catch (Exception e) { - Console.WriteLine(e); - } - } - } - - private static string GetMessage(IMonitor mon, string displayName) { - return mon.Status switch { - MonitorStatus.Up => $"🟢 {displayName} is UP.\n" + $"Outage duration: {mon.ResolvedAt.Subtract(mon.StartedAt).ToStringCustom()}", - - MonitorStatus.Recovering => $"🟡 {displayName} is recovering.", - MonitorStatus.Down => $"🔴 {displayName} is DOWN.\n" + $"Cause: {mon.LastValue}\n" + $"Outage started {mon.StartedAt:yyyy'-'MM'-'dd HH':'mm':'ss %K}", - MonitorStatus.Unknown => null, - MonitorStatus.Validating => null, - _ => null - }; - } - } - - public static class TimeSpanExtensions { - public static string ToStringCustom(this TimeSpan timeSpan) { - var retstr = $"{timeSpan.Seconds}s"; - if (timeSpan.Minutes > 0) - retstr = $"{timeSpan.Minutes}m {retstr}"; - if (Math.Floor(timeSpan.TotalHours) > 0) - retstr = $"{Math.Floor(timeSpan.TotalHours)}h {retstr}"; - - return retstr; - } - } -} \ No newline at end of file diff --git a/Monithor.api/Alerting/General.cs b/Monithor.api/Alerting/General.cs new file mode 100644 index 0000000..487a31f --- /dev/null +++ b/Monithor.api/Alerting/General.cs @@ -0,0 +1,29 @@ +using System; + +namespace Monithor.api.Alerting { + public static class General { + internal static string GetMessage(IMonitor mon, string displayName) { + return mon.Status switch { + MonitorStatus.Up => $"🟢 {displayName} is UP.\n" + $"Outage duration: {mon.ResolvedAt.Subtract(mon.StartedAt).ToStringCustom()}", + + MonitorStatus.Recovering => $"🟡 {displayName} is recovering.", + MonitorStatus.Down => $"🔴 {displayName} is DOWN.\n" + $"Cause: {mon.LastValue}\n" + $"Outage started {mon.StartedAt:yyyy'-'MM'-'dd HH':'mm':'ss %K}", + MonitorStatus.Unknown => null, + MonitorStatus.Validating => null, + _ => null + }; + } + } + + public static class TimeSpanExtensions { + public static string ToStringCustom(this TimeSpan timeSpan) { + var retstr = $"{timeSpan.Seconds}s"; + if (timeSpan.Minutes > 0) + retstr = $"{timeSpan.Minutes}m {retstr}"; + if (Math.Floor(timeSpan.TotalHours) > 0) + retstr = $"{Math.Floor(timeSpan.TotalHours)}h {retstr}"; + + return retstr; + } + } +} \ No newline at end of file diff --git a/Monithor.api/Alerting/ITarget.cs b/Monithor.api/Alerting/ITarget.cs new file mode 100644 index 0000000..db91caa --- /dev/null +++ b/Monithor.api/Alerting/ITarget.cs @@ -0,0 +1,6 @@ +namespace Monithor.api.Alerting { + public interface ITarget { + public void SendMessage(); + public IMonitor Monitor { get; set; } + } +} \ No newline at end of file diff --git a/Monithor.api/Alerting/MattermostWebhookTarget.cs b/Monithor.api/Alerting/MattermostWebhookTarget.cs new file mode 100644 index 0000000..892c749 --- /dev/null +++ b/Monithor.api/Alerting/MattermostWebhookTarget.cs @@ -0,0 +1,34 @@ +using System; +using System.Net; +using Telegram.Bot; +using Telegram.Bot.Types.Enums; +using Telegram.Bot.Types.ReplyMarkups; + +namespace Monithor.api.Alerting { + public class MattermostWebhookTarget : ITarget { + public MattermostWebhookTarget(string url, IMonitor monitor, string displayName, string username = "monithor-alerting", string channel = "") { + _url = url; + _channel = channel; + _username = username; + Monitor = monitor; + _displayName = displayName; + } + + private readonly string _url; + private readonly string _channel; + private readonly string _username; + public IMonitor Monitor { get; set; } + private readonly string _displayName; + + public void SendMessage() { + var message = General.GetMessage(Monitor, _displayName); + var json = $"{{ \"channel\": \"{_channel}\", \"username\": \"{_username}\", \"text\": \"{message}\" }}".Replace("\n", "\\n");; + try { + new WebClient().UploadString(_url, json); + } + catch (Exception e) { + Console.WriteLine(e); + } + } + } +} \ No newline at end of file diff --git a/Monithor.api/Alerting/TelegramTarget.cs b/Monithor.api/Alerting/TelegramTarget.cs new file mode 100644 index 0000000..441aeec --- /dev/null +++ b/Monithor.api/Alerting/TelegramTarget.cs @@ -0,0 +1,34 @@ +using System; +using Telegram.Bot; +using Telegram.Bot.Types.Enums; +using Telegram.Bot.Types.ReplyMarkups; + +namespace Monithor.api.Alerting { + public class TelegramTarget : ITarget { + public TelegramTarget(TelegramBotClient client, string chatId, IMonitor monitor, string statusPageRoute, string displayName) { + _client = client; + _chatId = chatId; + Monitor = monitor; + _statusPageRoute = statusPageRoute; + _displayName = displayName; + } + + public IMonitor Monitor { get; set; } + + private readonly TelegramBotClient _client; + private readonly string _chatId; + private readonly string _statusPageRoute; + private readonly string _displayName; + + public async void SendMessage() { + var statusPageBtn = new InlineKeyboardMarkup(InlineKeyboardButton.WithUrl("Open status page", $"https://{_statusPageRoute}")); + var message = General.GetMessage(Monitor, _displayName); + try { + await _client.SendTextMessageAsync(_chatId, message, ParseMode.Default, replyMarkup: statusPageBtn); + } + catch (Exception e) { + Console.WriteLine(e); + } + } + } +} \ No newline at end of file diff --git a/Monithor.api/Alerting/ZulipWebhookTarget.cs b/Monithor.api/Alerting/ZulipWebhookTarget.cs new file mode 100644 index 0000000..859373c --- /dev/null +++ b/Monithor.api/Alerting/ZulipWebhookTarget.cs @@ -0,0 +1,38 @@ +using System; +using System.Net; +using Telegram.Bot; +using Telegram.Bot.Types.Enums; +using Telegram.Bot.Types.ReplyMarkups; + +namespace Monithor.api.Alerting { + public class ZulipWebhookTarget : ITarget { + public ZulipWebhookTarget(string domain, string apikey, IMonitor monitor, string displayName, string stream, string topic = "monithor-alerting") { + _domain = domain; + _apikey = apikey; + _stream = stream; + _topic = topic; + Monitor = monitor; + _displayName = displayName; + } + + private readonly string _domain; + private readonly string _apikey; + private readonly string _stream; + private readonly string _topic; + public IMonitor Monitor { get; set; } + private readonly string _displayName; + + public void SendMessage() { + var message = General.GetMessage(Monitor, _displayName); + var json = $"{{ \"text\": \"{message}\" }}".Replace("\n", "\\n"); + try { + var client = new WebClient(); + client.Headers.Add("Content-Type", "application/json"); + client.UploadString($"https://{_domain}/api/v1/external/slack_incoming?api_key={_apikey}&stream={_stream}&topic={_topic}", json); + } + catch (Exception e) { + Console.WriteLine(e); + } + } + } +} \ No newline at end of file diff --git a/Monithor.api/Config.cs.template b/Monithor.api/Config.cs.template index 5d362ed..c23770f 100644 --- a/Monithor.api/Config.cs.template +++ b/Monithor.api/Config.cs.template @@ -20,7 +20,7 @@ namespace Monithor.api { new IcmpMonitor("placeholder-icmp", "host.your.domain"), }; - public static readonly List TelegramTargets = new() { + public static readonly List Targets = new() { new Alerting.TelegramTarget(TgClient, "1234", Monitors.First(p => p.Identifier == "placeholder-tcp"), "your.status.page", "SSH"), new Alerting.TelegramTarget(TgClient, "1234", Monitors.First(p => p.Identifier == "placeholder-icmp"), "your.status.page", "Server"), }; diff --git a/Monithor.api/DbProxy.cs b/Monithor.api/DbProxy.cs index 13b24ce..4e403f4 100644 --- a/Monithor.api/DbProxy.cs +++ b/Monithor.api/DbProxy.cs @@ -18,7 +18,7 @@ namespace Monithor.api { public static void ProcessMonitors(bool notify = true) { foreach (var monitor in Config.Monitors.FindAll(monitor => monitor.Update(monitor.GetFluxItems(_influx, "5m")))) { if (notify) { - Config.TelegramTargets.FindAll(p => p.Monitor == monitor).ForEach(p => p.SendMessage()); + Config.Targets.FindAll(p => p.Monitor == monitor).ForEach(p => p.SendMessage()); } } }