Browse Source

Add webhook integrations, refactor

dev
Laura Hausmann 5 months ago
parent
commit
bff422312c
Signed by: zotan GPG Key ID: D044E84C5BE01605
  1. 59
      Monithor.api/Alerting.cs
  2. 29
      Monithor.api/Alerting/General.cs
  3. 6
      Monithor.api/Alerting/ITarget.cs
  4. 34
      Monithor.api/Alerting/MattermostWebhookTarget.cs
  5. 34
      Monithor.api/Alerting/TelegramTarget.cs
  6. 38
      Monithor.api/Alerting/ZulipWebhookTarget.cs
  7. 2
      Monithor.api/Config.cs.template
  8. 2
      Monithor.api/DbProxy.cs

59
Monithor.api/Alerting.cs

@ -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;
}
}
}

29
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;
}
}
}

6
Monithor.api/Alerting/ITarget.cs

@ -0,0 +1,6 @@
namespace Monithor.api.Alerting {
public interface ITarget {
public void SendMessage();
public IMonitor Monitor { get; set; }
}
}

34
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);
}
}
}
}

34
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);
}
}
}
}

38
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);
}
}
}
}

2
Monithor.api/Config.cs.template

@ -20,7 +20,7 @@ namespace Monithor.api {
new IcmpMonitor("placeholder-icmp", "host.your.domain"),
};
public static readonly List<Alerting.TelegramTarget> TelegramTargets = new() {
public static readonly List<Alerting.ITarget> 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"),
};

2
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());
}
}
}

Loading…
Cancel
Save