5 Commits

Author SHA1 Message Date
ff998f9603 Remove MonA 2025-10-11 15:39:44 -07:00
39bc20bc25 gatus external-endpoints push main server 2025-05-02 14:23:48 -07:00
8cae455a50 gatus external-endpoints push 2025-04-30 12:01:41 -07:00
8311e26759 Heartbeat before each performance message
Updated readme
2025-04-24 17:21:38 -07:00
6eb36f44c5 Added Expected to push a percentage 2025-04-05 14:19:33 -07:00
12 changed files with 285 additions and 478 deletions

View File

@ -10,6 +10,7 @@
"**/node_modules": true
},
"cSpell.words": [
"Gatus"
"Gatus",
"Infineon"
]
}

View File

@ -16,7 +16,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="8.0.1" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.14" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.15" />
<PackageReference Include="System.Text.Json" Version="9.0.2" />
</ItemGroup>
</Project>

View File

@ -1,20 +1,29 @@
using System.Collections.ObjectModel;
using System.Net.Http.Headers;
using Gatus.To.MonA.Infineon.Monitoring.MonA;
using Gatus.To.MonA.Models;
namespace Gatus.To.MonA.Helpers;
internal static partial class HelperGatusToMona {
private static IMonIn? _MonIn;
private static HttpClient? _HttpClient;
private static string GetFile(AppSettings appSettings) =>
Path.Combine(appSettings.GatusToMonaConfiguration.Directory, appSettings.GatusConfiguration.FileName);
internal static bool UpdateCount(AppSettings appSettings, ILogger<Worker> logger, CancellationToken cancellationToken) {
private static void CreateEmptyFile(AppSettings appSettings) {
if (!Directory.Exists(appSettings.GatusToMonaConfiguration.Directory))
_ = Directory.CreateDirectory(appSettings.GatusToMonaConfiguration.Directory);
string file = GetFile(appSettings);
File.WriteAllText(file, string.Empty);
}
internal static bool UpdateCount(AppSettings appSettings, IHttpClientFactory httpClientFactory, ILogger<Worker> logger, CancellationToken cancellationToken) {
_HttpClient ??= httpClientFactory.CreateClient();
ReadOnlyCollection<string> successMatches = GetSuccessMatches(appSettings, logger, cancellationToken);
SendPerformanceMessage(appSettings, logger, successMatches, cancellationToken);
decimal value = GetValue(appSettings, successMatches);
SendPerformanceMessage(appSettings, logger, _HttpClient, value, cancellationToken);
return true;
}
@ -35,10 +44,15 @@ internal static partial class HelperGatusToMona {
continue;
if (value[^1] is not '0' and not '1')
continue;
logger.LogDebug(value);
logger.LogInformation("Line {line}: {value}",
76,
value);
if (line.EndsWith('1'))
results.Add(string.Concat('{', value));
}
logger.LogInformation("Line {line}: {results}",
82,
string.Join(Environment.NewLine, results));
return results.AsReadOnly();
}
@ -46,7 +60,7 @@ internal static partial class HelperGatusToMona {
string[] results;
FileStream fileStream = new(file, FileMode.Truncate);
HttpClient httpClient = new();
Task<Stream> streamTask = httpClient.GetStreamAsync(appSettings.GatusConfiguration.URL, cancellationToken);
Task<Stream> streamTask = httpClient.GetStreamAsync($"{appSettings.GatusConfiguration.BaseUniformResourceLocator}/metrics", cancellationToken);
streamTask.Wait(cancellationToken);
Task task = streamTask.Result.CopyToAsync(fileStream, cancellationToken);
task.Wait(cancellationToken);
@ -57,41 +71,41 @@ internal static partial class HelperGatusToMona {
return results.AsReadOnly();
}
private static void SendPerformanceMessage(AppSettings appSettings, ILogger<Worker> logger, ReadOnlyCollection<string> successMatches, CancellationToken cancellationToken) {
string performanceName = string.Concat(appSettings.MonAConfiguration.Resource, appSettings.MonAConfiguration.Suffix);
Task<HttpResponseMessage> httpResponseMessage = _MonIn.SendPerformanceMessage(appSettings.MonAConfiguration.Site,
appSettings.MonAConfiguration.Resource,
performanceName,
value: successMatches.Count,
description: string.Empty);
httpResponseMessage.Wait(cancellationToken);
if (httpResponseMessage.Result.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception(httpResponseMessage.Result.StatusCode.ToString());
Task<string> body = httpResponseMessage.Result.Content.ReadAsStringAsync(cancellationToken);
body.Wait(cancellationToken);
logger.LogDebug(body.Result);
private static decimal GetValue(AppSettings appSettings, ReadOnlyCollection<string> successMatches) {
decimal result;
decimal v = successMatches.Count / appSettings.MonAConfiguration.Expected;
result = Math.Round(v, 3) * 100;
return result;
}
internal static void Heartbeat(AppSettings appSettings, IHttpClientFactory httpClientFactory, ILogger<Worker> logger, State state, CancellationToken cancellationToken) {
_MonIn ??= MonIn.GetInstance(httpClientFactory);
CreateEmptyFile(appSettings);
Task<HttpResponseMessage> httpResponseMessage = _MonIn.SendStatus(appSettings.MonAConfiguration.Site,
appSettings.MonAConfiguration.Resource,
appSettings.MonAConfiguration.StateName,
state);
private static void SendPerformanceMessage(AppSettings appSettings, ILogger<Worker> logger, HttpClient httpClient, decimal value, CancellationToken cancellationToken) {
string success = value == 100 ? "true" : "false";
string error = value == 100 ? string.Empty : $"value: {value}%;";
// httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", appSettings.GatusConfiguration.Token);
// httpResponseMessage = httpClient.PostAsync($"{appSettings.GatusConfiguration.BaseUniformResourceLocator}/api/v1/endpoints/{appSettings.GatusConfiguration.Key}/external?success={success}&error={error}", null, cancellationToken);
// httpResponseMessage.Wait(cancellationToken);
// logger.LogInformation("Line {line}: {OriginalString} => {Resource} : {Key} ; {value}",
// 140,
// httpResponseMessage.Result.RequestMessage.RequestUri.OriginalString,
// appSettings.MonAConfiguration.Resource,
// appSettings.GatusConfiguration.Key,
// value);
// if (httpResponseMessage.Result.StatusCode != System.Net.HttpStatusCode.OK)
// throw new Exception(httpResponseMessage.Result.StatusCode.ToString());
// if (!string.IsNullOrEmpty(appSettings.GatusToGatusConfiguration.BaseUniformResourceLocator)
// && !string.IsNullOrEmpty(appSettings.GatusToGatusConfiguration.Key)
// && !string.IsNullOrEmpty(appSettings.GatusToGatusConfiguration.Token)) { }
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", appSettings.GatusToGatusConfiguration.Token);
Task<HttpResponseMessage> httpResponseMessage = httpClient.PostAsync($"{appSettings.GatusToGatusConfiguration.BaseUniformResourceLocator}/api/v1/endpoints/{appSettings.GatusToGatusConfiguration.Key}/external?success={success}&error={error}", null, cancellationToken);
httpResponseMessage.Wait(cancellationToken);
logger.LogInformation("Line {line}: {OriginalString} => {Resource} : {Key} ; {value}",
154,
httpResponseMessage.Result.RequestMessage.RequestUri.OriginalString,
appSettings.MonAConfiguration.Resource,
appSettings.GatusToGatusConfiguration.Key,
value);
if (httpResponseMessage.Result.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception(httpResponseMessage.Result.StatusCode.ToString());
Task<string> body = httpResponseMessage.Result.Content.ReadAsStringAsync(cancellationToken);
body.Wait(cancellationToken);
logger.LogDebug(body.Result);
}
private static void CreateEmptyFile(AppSettings appSettings) {
if (!Directory.Exists(appSettings.GatusToMonaConfiguration.Directory))
_ = Directory.CreateDirectory(appSettings.GatusToMonaConfiguration.Directory);
string file = GetFile(appSettings);
File.WriteAllText(file, string.Empty);
}
}

View File

@ -1,144 +0,0 @@
namespace Gatus.To.MonA.Infineon.Monitoring.MonA;
public interface IMonIn {
Task<HttpResponseMessage> SendStatus(string site, string resource, string stateName, State state);
Task<HttpResponseMessage> SendStatus(string site,
DateTime timeStamp,
string resource,
string stateName,
State state);
Task<HttpResponseMessage> SendStatus(string site,
string resource,
string stateName,
State state,
string description);
Task<HttpResponseMessage> SendStatus(string site,
DateTime timeStamp,
string resource,
string stateName,
State state,
string description);
Task<HttpResponseMessage> SendStatus(string site,
string resource,
string subResource,
string stateName,
State state);
Task<HttpResponseMessage> SendStatus(string site,
DateTime timeStamp,
string resource,
string subResource,
string stateName,
State state);
Task<HttpResponseMessage> SendStatus(string site,
string resource,
string subResource,
string stateName,
State state,
string description);
Task<HttpResponseMessage> SendStatus(string site,
DateTime? timeStamp,
string resource,
string subResource,
string stateName,
State state,
string description);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
string performanceName,
double value);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string performanceName,
double value);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
string performanceName,
double value,
string description);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string performanceName,
double value,
string description);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string performanceName,
double value,
int? interval);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
DateTime? timeStamp,
string performanceName,
double value,
string unit);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string performanceName,
double value,
string unit,
int? interval);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
string subResource,
string performanceName,
double value);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
string subResource,
string performanceName,
double value,
string description);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value,
int? interval);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value,
string unit);
Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value,
string description,
string unit,
int? interval);
}

View File

@ -1,250 +0,0 @@
using System.Globalization;
using System.Text;
namespace Gatus.To.MonA.Infineon.Monitoring.MonA;
public class MonIn : IMonIn {
private readonly string _MonInUrl;
private readonly HttpClient _HttpClient;
private static CultureInfo? _CultureInfo;
private static readonly Dictionary<string, MonIn> _Instances = [];
public const string MonInUrl = "http://moninhttp.{0}.infineon.com/input/text";
private static readonly DateTime _Utc1970DateTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public Task<HttpResponseMessage> SendStatus(string site, string resource, string stateName, State state) =>
SendStatus(site, new DateTime?(), resource, string.Empty, stateName, state, string.Empty);
public Task<HttpResponseMessage> SendStatus(string site,
DateTime timeStamp,
string resource,
string stateName,
State state) =>
SendStatus(site, new DateTime?(timeStamp), resource, string.Empty, stateName, state, string.Empty);
public Task<HttpResponseMessage> SendStatus(string site,
string resource,
string stateName,
State state,
string description) =>
SendStatus(site, new DateTime?(), resource, string.Empty, stateName, state, description);
public Task<HttpResponseMessage> SendStatus(string site,
DateTime timeStamp,
string resource,
string stateName,
State state,
string description) =>
SendStatus(site, new DateTime?(timeStamp), resource, string.Empty, stateName, state, description);
public Task<HttpResponseMessage> SendStatus(string site,
string resource,
string subResource,
string stateName,
State state) =>
SendStatus(site, new DateTime?(), resource, subResource, stateName, state, string.Empty);
public Task<HttpResponseMessage> SendStatus(string site,
DateTime timeStamp,
string resource,
string subResource,
string stateName,
State state) =>
SendStatus(site, new DateTime?(timeStamp), resource, subResource, stateName, state, string.Empty);
public Task<HttpResponseMessage> SendStatus(string site,
string resource,
string subResource,
string stateName,
State state,
string description) =>
SendStatus(site, new DateTime?(), resource, subResource, stateName, state, description);
public Task<HttpResponseMessage> SendStatus(
string site,
DateTime? timeStamp,
string resource,
string subResource,
string stateName,
State state,
string description) {
string statusMessage = CreateStatusMessage(site, timeStamp, resource, subResource, stateName, state.ToString(), description);
StringContent stringContent = new(statusMessage, Encoding.UTF8, "application/text");
lock (_HttpClient)
return _HttpClient.PostAsync(string.Format(_MonInUrl, site), stringContent);
}
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
string performanceName,
double value) =>
SendPerformanceMessage(site, new DateTime?(), resource, string.Empty, performanceName, value, string.Empty, string.Empty, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string performanceName,
double value) =>
SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, string.Empty, string.Empty, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
string performanceName,
double value,
string description) =>
SendPerformanceMessage(site, new DateTime?(), resource, string.Empty, performanceName, value, description, string.Empty, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string performanceName,
double value,
string description) =>
SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, description, string.Empty, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string performanceName,
double value,
int? interval) =>
SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, string.Empty, string.Empty, interval);
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
DateTime? timeStamp,
string performanceName,
double value,
string unit) =>
SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, string.Empty, unit, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string performanceName,
double value,
string unit,
int? interval) =>
SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, string.Empty, unit, interval);
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
string subResource,
string performanceName,
double value) =>
SendPerformanceMessage(site, new DateTime?(), resource, subResource, performanceName, value, string.Empty, string.Empty, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value) =>
SendPerformanceMessage(site, timeStamp, resource, subResource, performanceName, value, string.Empty, string.Empty, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
string resource,
string subResource,
string performanceName,
double value,
string description) =>
SendPerformanceMessage(site, new DateTime?(), resource, subResource, performanceName, value, description, string.Empty, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value,
int? interval) =>
SendPerformanceMessage(site, timeStamp, resource, subResource, performanceName, value, string.Empty, string.Empty, interval);
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value,
string unit) =>
SendPerformanceMessage(site, timeStamp, resource, subResource, performanceName, value, string.Empty, unit, new int?());
public Task<HttpResponseMessage> SendPerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value,
string description,
string unit,
int? interval) {
string performanceMessage = CreatePerformanceMessage(site, timeStamp, resource, subResource, performanceName, value, description, unit, interval);
StringContent stringContent = new(performanceMessage, Encoding.UTF8, "application/text");
lock (_HttpClient)
return _HttpClient.PostAsync(string.Format(_MonInUrl, site), stringContent);
}
private static string CreateStatusMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string stateName,
string state,
string description) {
StringBuilder stringBuilder = new();
if (string.IsNullOrEmpty(subResource))
_ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" {4} \n{5}", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), stateName.Trim(), state.Trim(), description.Trim());
else
_ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" \"{4}\" {5} \n{6}", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), subResource.Trim(), stateName.Trim(), state.Trim(), description.Trim());
return stringBuilder.ToString();
}
private static string CreatePerformanceMessage(string site,
DateTime? timeStamp,
string resource,
string subResource,
string performanceName,
double value,
string description,
string unit,
int? interval) {
StringBuilder stringBuilder = new();
if (string.IsNullOrEmpty(subResource)) {
if (unit.Equals(string.Empty) && !interval.HasValue)
_ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" {4} \n{5}", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), performanceName.Trim(), value, description.Trim());
else
_ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" {4} {5} {{interval={6}, unit={7}}}\n", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), performanceName.Trim(), value, description.Trim(), interval.HasValue ? interval.Value.ToString() : (object)string.Empty, unit.Trim());
} else if (unit.Equals(string.Empty) && !interval.HasValue)
_ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" \"{4}\" {5} \n{6}", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), subResource.Trim(), performanceName.Trim(), value, description.Trim());
else
_ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" \"{4}\" {5} {6} {{interval={7}, unit={8}}}\n", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), subResource.Trim(), performanceName.Trim(), value, description.Trim(), interval.HasValue ? interval.Value.ToString() : (object)string.Empty, unit.Trim());
return stringBuilder.ToString();
}
public static MonIn GetInstance(IHttpClientFactory httpClientFactory, string url = MonInUrl) {
MonIn instance;
if (_Instances.ContainsKey(url)) {
instance = _Instances[url];
} else {
lock (_Instances) {
if (!_Instances.ContainsKey(url)) {
instance = new MonIn(httpClientFactory, url);
_Instances.Add(url, instance);
} else
instance = _Instances[url];
}
}
return instance;
}
private MonIn(IHttpClientFactory httpClientFactory, string url) {
_MonInUrl = url;
_CultureInfo = new CultureInfo("en-US");
_HttpClient = httpClientFactory.CreateClient();
}
private static string GetDateTimeNowAsPosix(DateTime timeStamp) {
if (timeStamp > DateTime.Now)
timeStamp = DateTime.Now;
return ((int)timeStamp.ToUniversalTime().Subtract(_Utc1970DateTime).TotalSeconds).ToString(CultureInfo.InvariantCulture);
}
}

View File

@ -1,10 +0,0 @@
namespace Gatus.To.MonA.Infineon.Monitoring.MonA;
public enum State {
Up,
Ok,
Warning,
Critical,
Down,
Unknown,
}

View File

@ -4,6 +4,7 @@ using System.Text.Json.Serialization;
namespace Gatus.To.MonA.Models;
public record AppSettings(GatusConfiguration GatusConfiguration,
GatusToGatusConfiguration GatusToGatusConfiguration,
GatusToMonaConfiguration GatusToMonaConfiguration,
MonAConfiguration MonAConfiguration) {
@ -11,10 +12,12 @@ public record AppSettings(GatusConfiguration GatusConfiguration,
AppSettings result;
#pragma warning disable IL3050, IL2026
GatusConfiguration? gatusConfiguration = configurationRoot.GetSection(nameof(GatusConfiguration)).Get<GatusConfiguration>();
GatusToGatusConfiguration? gatusToGatusConfiguration = configurationRoot.GetSection(nameof(GatusToGatusConfiguration)).Get<GatusToGatusConfiguration>();
GatusToMonaConfiguration? gatusToMonaConfiguration = configurationRoot.GetSection(nameof(GatusToMonaConfiguration)).Get<GatusToMonaConfiguration>();
MonAConfiguration? monAConfiguration = configurationRoot.GetSection(nameof(MonAConfiguration)).Get<MonAConfiguration>();
#pragma warning restore IL3050, IL2026
if (gatusConfiguration is null
|| gatusToGatusConfiguration is null
|| gatusToMonaConfiguration is null
|| monAConfiguration is null
|| gatusToMonaConfiguration?.Company is null) {
@ -29,6 +32,7 @@ public record AppSettings(GatusConfiguration GatusConfiguration,
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
}
result = new(gatusConfiguration,
gatusToGatusConfiguration,
gatusToMonaConfiguration,
monAConfiguration);
Verify(result);
@ -39,7 +43,9 @@ public record AppSettings(GatusConfiguration GatusConfiguration,
if (string.IsNullOrEmpty(appSettings.GatusToMonaConfiguration.Company))
throw new Exception("Company name must have a value!");
if (appSettings.MonAConfiguration.Minutes < 1)
throw new Exception("MonA Minutes must have a value more than one!");
throw new Exception("MonA Minutes must have a value more than zero!");
if (appSettings.MonAConfiguration.Expected < 1)
throw new Exception("MonA Expected must have a value more than zero!");
TimeSpan timeSpan = new(DateTime.MinValue.AddMinutes(appSettings.MonAConfiguration.Minutes).Ticks - DateTime.MinValue.Ticks);
if (appSettings.GatusToMonaConfiguration.MillisecondsDelay < timeSpan.TotalMilliseconds)
throw new Exception($"MonA doesn't support more than once per five minutes ({timeSpan.TotalMilliseconds})!");

View File

@ -3,9 +3,9 @@ using System.Text.Json.Serialization;
namespace Gatus.To.MonA.Models;
public record GatusConfiguration(string FileName,
string Metric,
string URL) {
public record GatusConfiguration(string BaseUniformResourceLocator,
string FileName,
string Metric) {
public override string ToString() {
string result = JsonSerializer.Serialize(this, GatusConfigurationSourceGenerationContext.Default.GatusConfiguration);

View File

@ -0,0 +1,20 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Gatus.To.MonA.Models;
public record GatusToGatusConfiguration(string? BaseUniformResourceLocator,
string? Key,
string? Token) {
public override string ToString() {
string result = JsonSerializer.Serialize(this, GatusToGatusConfigurationSourceGenerationContext.Default.GatusToGatusConfiguration);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(GatusToGatusConfiguration))]
internal partial class GatusToGatusConfigurationSourceGenerationContext : JsonSerializerContext {
}

View File

@ -3,7 +3,8 @@ using System.Text.Json.Serialization;
namespace Gatus.To.MonA.Models;
public record MonAConfiguration(int Minutes,
public record MonAConfiguration(decimal Expected,
int Minutes,
string Resource,
string Site,
string StateName,

208
README.md
View File

@ -1,20 +1,196 @@
# Introduction
TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.
---
created: 2024-11-07T00:14:29.000Z
type: note
---
# Getting Started
TODO: Guide users through getting your code up and running on their own system. In this section you can talk about:
1. Installation process
2. Software dependencies
3. Latest releases
4. API references
# Gatus
# Build and Test
TODO: Describe and show how to build your code and run the tests.
Gatus is an advanced automated status page that lets you monitor your applications and configure alerts to notify you if there's an issue
# Contribute
TODO: Explain how other users and developers can contribute to make your code better.
## Links
If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files:
- [ASP.NET Core](https://github.com/aspnet/Home)
- [Visual Studio Code](https://github.com/Microsoft/vscode)
- [Chakra Core](https://github.com/Microsoft/ChakraCore)
- [gatus.io](https://gatus.io/)
- [github](https://github.com/TwiN/gatus)
- [techno-tim](https://technotim.live/posts/gatus-uptime-monitoring/#gatus-config)
## Install
- [ ] CasaOS
- [x] Docker
- [ ] Home Assistant
- [ ] lxc
- [ ] Snap
- [ ] TTeck
- [ ] Umbrel
- [ ] Yu No Host
## Gatus
- Clone repo from github or local ADO
- Build using go lang
- Copy exe only to server
- Create *.yaml file for configuration
## NSSM - the Non-Sucking Service Manager
- Copy zip to server and extract to directory
- Run a cmd window with administrator access
### ecFIsysadmin-10.95.140.37-messa010ec(OI-Metrology-Viewer)
```bash 1744999536292 = 638805963362920000 = 2025-1.Spring = Fri Apr 18 2025 11:05:35 GMT-0700 (Mountain Standard Time)
mklink /J "D:\web-sites\Gatus\current" "D:\web-sites\Gatus\v5.17.0"
```
```bash 1744999568664 = 638805963686640000 = 2025-1.Spring = Fri Apr 18 2025 11:06:08 GMT-0700 (Mountain Standard Time)
# cd "C:\Users\ecfisysadmin\AppData\Local\IFXApps\nssm-2.24\win64"
C:
cd "C:\Windows\System32\config\systemprofile\AppData\Local\IFXApps\nssm-2.24\win64"
nssm install gatus
nssm edit gatus
```
```yaml NSSM-Application 1743806212388 = 638794030123880000 = 2025-1.Spring = Fri Apr 04 2025 15:36:51 GMT-0700 (Mountain Standard Time)
Path: D:\web-sites\Gatus\current\gatus.exe
Startup Directory: D:\web-sites\Gatus\current
```
```yml NSSM-Details 1743806328796 = 638794031287960000 = 2025-1.Spring = Fri Apr 04 2025 15:38:48 GMT-0700 (Mountain Standard Time)
Startup type: Automatic (Delay Start)
```
```yml NSSM-I/O 1743806328796 = 638794031287960000 = 2025-1.Spring = Fri Apr 04 2025 15:38:48 GMT-0700 (Mountain Standard Time)
Input (stdin):
Output (stdout): D:\web-sites\Gatus\current\logs\service.out.log
Error (stderr): D:\web-sites\Gatus\current\logs\service.error.log
```
```yml NSSM-Environment 1743806359765 = 638794031597650000 = 2025-1.Spring = Fri Apr 04 2025 15:39:19 GMT-0700 (Mountain Standard Time)
GATUS_CONFIG_PATH=./oi-metrology-viewer.yaml
```
```bash Administrator 1743806328796 = 638794031287960000 = 2025-1.Spring = Fri Apr 04 2025 15:38:48 GMT-0700 (Mountain Standard Time)
sc start gatus
sc query gatus
sc stop gatus
sc start gatus
# systemctl start gatus
```
```bash 1745023773786 = 638806205737860000 = 2025-1.Spring = Fri Apr 18 2025 17:49:33 GMT-0700 (Mountain Standard Time)
mklink /J "D:\web-sites\Gatus\.Gatus-to-MonA" "C:\Windows\System32\config\systemProfile\AppData\Local\IFXApps\Gatus-to-MonA"
mkdir "D:/Tmp/Gatus-to-MonA"
```
## Nginx
- Add new server to proxy pass to 8081
- Test nginx
- Restart nginx
## MonA
- Create generic resource type
- On overview page click edit then click update without making any changes
- Wait a hour
- On data page click Edit Resource Name then click update without making any changes
- Wait a day
- On overview page click use for main status (Heartbeat)
- Refresh config page and search for threshold
- Define threshold
## Sdk="Microsoft.NET.Sdk.Worker"
- Build with AOT task
- Copy publish directory to server
- Copy / edit secrets file
- Verify windows event viewer entry for company name
```bash 1743817269373 = 638794140693730000 = 2025-1.Spring = Fri Apr 04 2025 18:41:08 GMT-0700 (Mountain Standard Time)
sc.exe create "Gatus-to-MonA" binpath="C:\Windows\System32\config\systemprofile\AppData\Local\IFXApps\Gatus-to-MonA\Gatus-to-MonA.exe"
```
## MonA Instances
- [MES_APC_GATUS](https://mona.auc.infineon.com/auc/systems/563556/dependencies?config=true)
- [messa013ec.infineon.com](http://messa013ec.infineon.com:8082)
- [MES_EAF_GATUS](https://mona.auc.infineon.com/auc/systems/563493/dependencies?config=true)
- [messa08ec.infineon.com](http://messa08ec.infineon.com:8082)
- [MES_EAF_STAGE_GATUS](https://mona.auc.infineon.com/auc/systems/563516/dependencies?config=true)
- [mestsa07ec.infineon.com](http://mestsa07ec.infineon.com:8082)
- [MES_FAB_APPROVAL_SYSTEM_GATUS](https://mona.auc.infineon.com/auc/systems/563517/dependencies?config=true)
- [messa016ec.infineon.com](http://messa016ec.infineon.com:8082)
- https://messa016ec.infineon.com
- [MES_FAB_TIME_GATUS](https://mona.auc.infineon.com/auc/systems/563518/dependencies?config=true)
- [messa004.infineon.com](http://messa004.infineon.com:8082)
- [MES_INFINITY_QS_SI_GATUS](https://mona.auc.infineon.com/auc/systems/563519/dependencies?config=true)
- [messa04ec.infineon.com](http://messa04ec.infineon.com:8082)
- [MES_OPEN_INSIGHT_GATUS](https://mona.auc.infineon.com/auc/systems/563520/dependencies?config=true)
- GATUS_CONFIG_PATH=./oi.yaml
- [messa01ec.infineon.com](http://messa01ec.infineon.com:8082)
- http://messa014.infineon.com/api/heartbeat
- http://messa014.infineon.com/API/RemoteHealthCheck/Mona/MonaEngines/DB-EN1
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN10
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN11
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN12
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN2
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN3
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN4
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN5
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN6
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN7
- http://messa014.infineon.com/api/RemoteHealthCheck/Mona/MonaEngines/DB-EN9
- [MES_OPEN_INSIGHT_DEV_GATUS](https://mona.auc.infineon.com/auc/systems/563521/dependencies?config=true)
- [mestsa01ec.infineon.com](http://mestsa01ec.infineon.com:8082)
- [MES_OI_METROLOGY_VIEWER_GATUS](https://mona.auc.infineon.com/auc/systems/557090/dependencies?config=true)
- [messa010ec.infineon.com](http://messa010ec.infineon.com:8082)
- [MES_OI_WEB_SERVICES_GATUS](https://mona.auc.infineon.com/auc/systems/563522/dependencies?config=true)
- [messa020ec.infineon.com](http://messa020ec.infineon.com:8082)
- ~~messa014.infineon.com~~
- https://messa014.infineon.com/scan
- https://messa014.infineon.com:50184
- https://messa014.infineon.com:5022
- [LEO_EAF_GATUS](https://mona.auc.infineon.com/auc/systems/563522/dependencies?config=true)
- [leosaec17.infineon.com](http://leosaec17.infineon.com:8082)
## Prometheus config to consume Gatus metrics
- [prometheus](https://github.com/TwiN/gatus/blob/master/.examples/docker-compose-grafana-prometheus/README.md)
## Outline
### Goal
- Monitor TLS Cert
### Options
- Uptime Kuma
- Configuration is GUI driven
- Prometheus
- Not as easy to get started
- Grafana
- Too many features
- Open source but still have to login to use
### Benefits
- [x] Open Source
- [x] Written in GoLang
- [x] Doesn't need WAN connectivity
- [x] Keeps history with simple graph
- [x] Metrics output built for Prometheus
- [x] Sends e-mail alerts and has other alerting
- [x] Check status more often than five minute intervals
- [x] Single Config file that can be put in source control
- [x] Can wait for pushed data as well as default pull data
- [x] Simple GUI (website) that can be accessed outside server
- [x] Badge api that can be embedded in website (see oi server?)
- [x] Easy deployment [one binary, one config, runs via Non-Sucking Service Manager (nssm) and outputs sqlite files]
### Drawbacks
- [x] Another item to manage
- [x] Not part of the target solution
- [x] Haven't figured out how to push to MonIn directly with both heartbeat and performance

View File

@ -8,7 +8,6 @@ namespace Gatus.To.MonA;
public partial class Worker : BackgroundService {
private bool? _First;
private readonly bool _IsWindowsService;
private readonly ILogger<Worker> _Logger;
private readonly AppSettings _AppSettings;
@ -20,19 +19,16 @@ public partial class Worker : BackgroundService {
_HttpClientFactory = httpClientFactory;
logger.LogInformation(string.Join(Environment.NewLine, collection));
try { logger.LogInformation("<{folder}>", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); } catch (Exception) { }
_First = null;
_IsWindowsService = collection.Contains(nameof(WindowsServiceLifetime));
}
public override Task StopAsync(CancellationToken cancellationToken) {
if (_AppSettings.GatusToMonaConfiguration.Helper == nameof(Helpers.HelperGatusToMona))
Helpers.HelperGatusToMona.Heartbeat(_AppSettings, _HttpClientFactory, _Logger, Infineon.Monitoring.MonA.State.Down, cancellationToken);
return base.StopAsync(cancellationToken);
}
public override Task StopAsync(CancellationToken cancellationToken) =>
base.StopAsync(cancellationToken);
private async Task Body(CancellationToken cancellationToken) {
if (!_IsWindowsService) {
_Logger.LogInformation("Set break point and skip to run {_AppSettings.GatusToMonaConfiguration.Helper}!", _AppSettings.GatusToMonaConfiguration.Helper);
BodyInner(cancellationToken);
throw new EvaluateException($"Set break point and skip to run {_AppSettings.GatusToMonaConfiguration.Helper}!");
}
if (!_IsWindowsService) {
@ -42,23 +38,20 @@ public partial class Worker : BackgroundService {
}
}
while (_IsWindowsService && !cancellationToken.IsCancellationRequested) {
try {
BodyInner(cancellationToken);
await Task.Delay(_AppSettings.GatusToMonaConfiguration.MillisecondsDelay, cancellationToken);
} catch (Exception ex) { _Logger.LogError(ex, "Unexpected Error!"); }
}
}
private void BodyInner(CancellationToken cancellationToken) {
_Logger.LogInformation("A) Next execute will be at {date}", DateTime.Now.AddMilliseconds(_AppSettings.GatusToMonaConfiguration.MillisecondsDelay).ToString("yyyy-MM-dd hh:mm:ss.fff tt"));
if (_First is null || _First.Value) {
_First = false;
if (_AppSettings.GatusToMonaConfiguration.Helper == nameof(Helpers.HelperGatusToMona))
Helpers.HelperGatusToMona.Heartbeat(_AppSettings, _HttpClientFactory, _Logger, Infineon.Monitoring.MonA.State.Up, cancellationToken);
}
if (!Directory.Exists(_AppSettings.GatusToMonaConfiguration.Directory))
_ = Directory.CreateDirectory(_AppSettings.GatusToMonaConfiguration.Directory);
else {
_ = _AppSettings.GatusToMonaConfiguration.Helper switch {
nameof(Helpers.HelperGatusToMona) => Helpers.HelperGatusToMona.UpdateCount(_AppSettings, _Logger, cancellationToken),
nameof(Helpers.HelperGatusToMona) => Helpers.HelperGatusToMona.UpdateCount(_AppSettings, _HttpClientFactory, _Logger, cancellationToken),
_ => throw new NotSupportedException()
};
}