Made certain config options editable in the app config.

This commit is contained in:
2026-07-03 09:55:38 +02:00
parent 2dab6f970a
commit b6cc34be27
9 changed files with 100 additions and 16 deletions
+22 -2
View File
@@ -145,6 +145,25 @@ File: `src\HostAvailabilityMonitor\appsettings.json`
- `HipVirtualMachines`: optional static VM checks - `HipVirtualMachines`: optional static VM checks
- `Targets`: endpoints to probe - `Targets`: endpoints to probe
### Runtime section
Important fields in `Runtime`:
- `MaxConcurrency`: maximum number of parallel endpoint checks
- `DefaultValidateUncPathAccess`: default for UNC targets without their own `ValidateUncPathAccess` value
- `NonZeroExitCodeOnAnyFailure`: exit with code `2` when endpoint failures are found
- `NonZeroExitCodeOnExecutionError`: exit with code `1` on technical execution errors
- `StateDirectory`: directory for the state file
- `StateFileName`: state file name, default `monitor-state.json`
### Logging section
Important fields in `Logging`:
- `LogDirectory`: directory for rolling log files
- `FilePrefix`: prefix for daily log files
- `RetentionDays`: number of daily log files to retain, default `30`; `0` disables automatic cleanup
### Email section ### Email section
Important fields in `Email`: Important fields in `Email`:
@@ -330,12 +349,13 @@ It contains:
- `Logging` - `Logging`
- `EventLog` - `EventLog`
- `Email` - `Email`
- `HipVirtualMachines`
`Targets` is rebuilt by the generator at runtime. `Targets` is rebuilt by the generator at runtime.
Important: Important:
When the generator writes the monitor JSON, the daily summary options and static HIP VM settings are also copied into the generated target file. That means `GeneratedMonitorConfig.Email.SendDailySummary`, `DailySummaryHourLocal`, `DailySummaryMinuteLocal`, and `GeneratedMonitorConfig.HipVirtualMachines` flow directly into the output monitor configuration. When the generator writes the monitor JSON, runtime, logging, daily summary, and static HIP VM settings are also copied into the generated target file. That means values such as `GeneratedMonitorConfig.Runtime.StateFileName`, `GeneratedMonitorConfig.Logging.RetentionDays`, `GeneratedMonitorConfig.Email.SendDailySummary`, `DailySummaryHourLocal`, `DailySummaryMinuteLocal`, and `GeneratedMonitorConfig.HipVirtualMachines` flow directly into the output monitor configuration.
--- ---
@@ -472,7 +492,7 @@ The generator is designed defensively:
The monitor is also defensive: The monitor is also defensive:
- daily rolling logs - daily rolling logs
- default retention of 5 days - default retention of 30 days, configurable through `Logging.RetentionDays`
- event log writes are best effort only - event log writes are best effort only
- state file is written atomically - state file is written atomically
- failure/recovery emails follow explicit notification rules - failure/recovery emails follow explicit notification rules
+22 -2
View File
@@ -145,6 +145,25 @@ Datei: `src\HostAvailabilityMonitor\appsettings.json`
- `HipVirtualMachines`: optionale statische VM-Prüfungen - `HipVirtualMachines`: optionale statische VM-Prüfungen
- `Targets`: die zu prüfenden Endpunkte - `Targets`: die zu prüfenden Endpunkte
### Runtime
Wichtige Felder im Abschnitt `Runtime`:
- `MaxConcurrency`: maximale Anzahl paralleler Endpoint-Checks
- `DefaultValidateUncPathAccess`: Standardwert fuer UNC-Targets ohne eigenen `ValidateUncPathAccess`-Wert
- `NonZeroExitCodeOnAnyFailure`: bei fachlichen DOWN-Ergebnissen mit Exitcode `2` beenden
- `NonZeroExitCodeOnExecutionError`: bei technischen Ausfuehrungsfehlern mit Exitcode `1` beenden
- `StateDirectory`: Verzeichnis fuer die Statusdatei
- `StateFileName`: Dateiname der Statusdatei, standardmaessig `monitor-state.json`
### Logging
Wichtige Felder im Abschnitt `Logging`:
- `LogDirectory`: Verzeichnis fuer die Rolling-Logdateien
- `FilePrefix`: Prefix der taeglichen Logdateien
- `RetentionDays`: Anzahl der aufzubewahrenden taeglichen Logdateien, standardmaessig `30`; `0` deaktiviert die automatische Bereinigung
### Email ### Email
Wichtige Felder im Abschnitt `Email`: Wichtige Felder im Abschnitt `Email`:
@@ -330,12 +349,13 @@ Hier werden gepflegt:
- `Logging` - `Logging`
- `EventLog` - `EventLog`
- `Email` - `Email`
- `HipVirtualMachines`
`Targets` wird vom Generator zur Laufzeit neu erzeugt. `Targets` wird vom Generator zur Laufzeit neu erzeugt.
Wichtig: Wichtig:
Wenn der Generator die Monitor-JSON erzeugt, werden auch die Felder für die Tagesstatus-Mail und die statische HIP-VM-Prüfung mit erzeugt. Das heißt: `GeneratedMonitorConfig.Email.SendDailySummary`, `DailySummaryHourLocal`, `DailySummaryMinuteLocal` und `GeneratedMonitorConfig.HipVirtualMachines` werden direkt in die Zielkonfiguration übernommen. Wenn der Generator die Monitor-JSON erzeugt, werden auch Runtime-, Logging-, Tagesstatus-Mail- und statische HIP-VM-Felder mit erzeugt. Das heißt: Werte wie `GeneratedMonitorConfig.Runtime.StateFileName`, `GeneratedMonitorConfig.Logging.RetentionDays`, `GeneratedMonitorConfig.Email.SendDailySummary`, `DailySummaryHourLocal`, `DailySummaryMinuteLocal` und `GeneratedMonitorConfig.HipVirtualMachines` werden direkt in die Zielkonfiguration übernommen.
--- ---
@@ -472,7 +492,7 @@ Der Generator ist defensiv gebaut:
Der Monitor ist ebenfalls defensiv gebaut: Der Monitor ist ebenfalls defensiv gebaut:
- Rolling-Dateilog mit täglicher Rotation - Rolling-Dateilog mit täglicher Rotation
- Retention standardmäßig 5 Tage - Retention standardmäßig 30 Tage, konfigurierbar über `Logging.RetentionDays`
- Eventlog-Schreiben nur best effort - Eventlog-Schreiben nur best effort
- Statusdatei mit atomischem Schreiben - Statusdatei mit atomischem Schreiben
- Failure-/Recovery-Mails nur bei definierten Bedingungen - Failure-/Recovery-Mails nur bei definierten Bedingungen
+3 -1
View File
@@ -86,7 +86,7 @@ Diese Struktur ist bewusst einfach gehalten, damit das Repository sauber in **Gi
- Task-Scheduler-tauglich - Task-Scheduler-tauglich
- tägliche Logrotation - tägliche Logrotation
- Log-Retention standardmäßig 5 Tage - Log-Retention standardmäßig 30 Tage
- Windows Application Event Log - Windows Application Event Log
- SMTP-Mails bei DOWN, Recovery (`DOWN -> UP`) und täglichem Status - SMTP-Mails bei DOWN, Recovery (`DOWN -> UP`) und täglichem Status
- SMTP-Sendports bzw. reine E-Mail-Empfaengerlisten werden vom Generator uebersprungen und vom Monitor defensiv nur als `Skipped` protokolliert, nicht alarmiert - SMTP-Sendports bzw. reine E-Mail-Empfaengerlisten werden vom Generator uebersprungen und vom Monitor defensiv nur als `Skipped` protokolliert, nicht alarmiert
@@ -341,6 +341,8 @@ Wichtige Felder:
- `BizTalk.ApplicationMappings`: Mapping von BizTalk-Anwendungsnamen auf fachliche App-Namen - `BizTalk.ApplicationMappings`: Mapping von BizTalk-Anwendungsnamen auf fachliche App-Namen
- `Output.Path`: Pfad der zu erzeugenden Monitor-JSON - `Output.Path`: Pfad der zu erzeugenden Monitor-JSON
- `GeneratedMonitorConfig`: Vorlage für Logging, Runtime, Event Log und Mail des Monitors - `GeneratedMonitorConfig`: Vorlage für Logging, Runtime, Event Log und Mail des Monitors
- `GeneratedMonitorConfig.Logging.RetentionDays`: Aufbewahrung der taeglichen Monitor-Logdateien, standardmaessig `30`
- `GeneratedMonitorConfig.Runtime.StateFileName`: Dateiname der Statusdatei, falls mehrere Monitor-Konfigurationen getrennten Zustand brauchen
- `GeneratedMonitorConfig.HipVirtualMachines`: statische HIP-VM-Prüfung in der generierten Monitor-JSON einschalten - `GeneratedMonitorConfig.HipVirtualMachines`: statische HIP-VM-Prüfung in der generierten Monitor-JSON einschalten
- `GeneratedMonitorConfig.Email.SendDailySummary`: tägliche Status-Mail in der generierten Monitor-JSON einschalten - `GeneratedMonitorConfig.Email.SendDailySummary`: tägliche Status-Mail in der generierten Monitor-JSON einschalten
- `GeneratedMonitorConfig.Email.DailySummaryHourLocal`: lokale Uhrzeit der Tageszusammenfassung - `GeneratedMonitorConfig.Email.DailySummaryHourLocal`: lokale Uhrzeit der Tageszusammenfassung
@@ -213,7 +213,7 @@ namespace BizTalkMonitorConfigGenerator.Configuration
/// <summary> /// <summary>
/// Gets or sets the number of daily generator log files to retain. /// Gets or sets the number of daily generator log files to retain.
/// </summary> /// </summary>
public int RetentionDays { get; set; } = 5; public int RetentionDays { get; set; } = 30;
} }
/// <summary> /// <summary>
@@ -424,6 +424,23 @@ namespace BizTalkMonitorConfigGenerator.Configuration
configuration.Runtime.MaxConcurrency = 1; configuration.Runtime.MaxConcurrency = 1;
} }
if (string.IsNullOrWhiteSpace(configuration.Runtime.StateDirectory))
{
configuration.Runtime.StateDirectory = "state";
}
if (string.IsNullOrWhiteSpace(configuration.Runtime.StateFileName))
{
configuration.Runtime.StateFileName = "monitor-state.json";
}
if (Path.IsPathRooted(configuration.Runtime.StateFileName)
|| configuration.Runtime.StateFileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0
|| configuration.Runtime.StateFileName.IndexOfAny(new[] { '\\', '/' }) >= 0)
{
throw new InvalidOperationException("GeneratedMonitorConfig.Runtime.StateFileName muss ein Dateiname ohne Pfadanteile sein.");
}
if (configuration.Logging.RetentionDays < 0) if (configuration.Logging.RetentionDays < 0)
{ {
throw new InvalidOperationException("GeneratedMonitorConfig.Logging.RetentionDays darf nicht negativ sein."); throw new InvalidOperationException("GeneratedMonitorConfig.Logging.RetentionDays darf nicht negativ sein.");
@@ -493,7 +510,8 @@ namespace BizTalkMonitorConfigGenerator.Configuration
DefaultValidateUncPathAccess = configuration.Runtime.DefaultValidateUncPathAccess, DefaultValidateUncPathAccess = configuration.Runtime.DefaultValidateUncPathAccess,
NonZeroExitCodeOnAnyFailure = configuration.Runtime.NonZeroExitCodeOnAnyFailure, NonZeroExitCodeOnAnyFailure = configuration.Runtime.NonZeroExitCodeOnAnyFailure,
NonZeroExitCodeOnExecutionError = configuration.Runtime.NonZeroExitCodeOnExecutionError, NonZeroExitCodeOnExecutionError = configuration.Runtime.NonZeroExitCodeOnExecutionError,
StateDirectory = configuration.Runtime.StateDirectory StateDirectory = configuration.Runtime.StateDirectory,
StateFileName = configuration.Runtime.StateFileName
}, },
Logging = new LoggingOptions Logging = new LoggingOptions
{ {
+1 -1
View File
@@ -241,7 +241,7 @@ namespace BizTalkMonitorConfigGenerator
try try
{ {
var directory = ResolvePath(baseDirectory ?? AppDomain.CurrentDomain.BaseDirectory, "logs"); var directory = ResolvePath(baseDirectory ?? AppDomain.CurrentDomain.BaseDirectory, "logs");
var fallbackLogger = new GeneratorFileLogger(directory, "biztalk-monitor-config-generator-startup", 5, "BizTalkMonitorConfigGenerator", "Startup"); var fallbackLogger = new GeneratorFileLogger(directory, "biztalk-monitor-config-generator-startup", 30, "BizTalkMonitorConfigGenerator", "Startup");
fallbackLogger.Error("Generator konnte nicht gestartet werden. Konfiguration=" + (configPath ?? "(nicht aufgeloest)") + ". Fehler=" + exception.GetType().Name + ": " + exception.Message); fallbackLogger.Error("Generator konnte nicht gestartet werden. Konfiguration=" + (configPath ?? "(nicht aufgeloest)") + ". Fehler=" + exception.GetType().Name + ": " + exception.Message);
fallbackLogger.Error("Details: " + exception); fallbackLogger.Error("Details: " + exception);
WriteConsoleInfo("Fallback-Log geschrieben: " + BuildLogFilePreview(directory, "biztalk-monitor-config-generator-startup")); WriteConsoleInfo("Fallback-Log geschrieben: " + BuildLogFilePreview(directory, "biztalk-monitor-config-generator-startup"));
@@ -4,7 +4,7 @@
"Logging": { "Logging": {
"LogDirectory": "logs", "LogDirectory": "logs",
"FilePrefix": "biztalk-monitor-config-generator", "FilePrefix": "biztalk-monitor-config-generator",
"RetentionDays": 5 "RetentionDays": 30
}, },
"EventLog": { "EventLog": {
"Enabled": true, "Enabled": true,
@@ -52,12 +52,13 @@
"DefaultValidateUncPathAccess": false, "DefaultValidateUncPathAccess": false,
"NonZeroExitCodeOnAnyFailure": false, "NonZeroExitCodeOnAnyFailure": false,
"NonZeroExitCodeOnExecutionError": true, "NonZeroExitCodeOnExecutionError": true,
"StateDirectory": "state" "StateDirectory": "state",
"StateFileName": "monitor-state.json"
}, },
"Logging": { "Logging": {
"LogDirectory": "logs", "LogDirectory": "logs",
"FilePrefix": "host-availability-monitor", "FilePrefix": "host-availability-monitor",
"RetentionDays": 5 "RetentionDays": 30
}, },
"EventLog": { "EventLog": {
"Enabled": true, "Enabled": true,
@@ -158,6 +158,23 @@ namespace HostAvailabilityMonitor.Configuration
Runtime.MaxConcurrency = 1; Runtime.MaxConcurrency = 1;
} }
if (string.IsNullOrWhiteSpace(Runtime.StateDirectory))
{
Runtime.StateDirectory = "state";
}
if (string.IsNullOrWhiteSpace(Runtime.StateFileName))
{
Runtime.StateFileName = "monitor-state.json";
}
if (Path.IsPathRooted(Runtime.StateFileName)
|| Runtime.StateFileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0
|| Runtime.StateFileName.IndexOfAny(new[] { '\\', '/' }) >= 0)
{
throw new InvalidOperationException("Runtime.StateFileName muss ein Dateiname ohne Pfadanteile sein.");
}
if (HipVirtualMachines == null) if (HipVirtualMachines == null)
{ {
HipVirtualMachines = new HipVirtualMachineOptions(); HipVirtualMachines = new HipVirtualMachineOptions();
@@ -286,6 +303,11 @@ namespace HostAvailabilityMonitor.Configuration
/// Gets or sets the state directory path. /// Gets or sets the state directory path.
/// </summary> /// </summary>
public string StateDirectory { get; set; } = "state"; public string StateDirectory { get; set; } = "state";
/// <summary>
/// Gets or sets the state file name inside the configured state directory.
/// </summary>
public string StateFileName { get; set; } = "monitor-state.json";
} }
/// <summary> /// <summary>
@@ -306,7 +328,7 @@ namespace HostAvailabilityMonitor.Configuration
/// <summary> /// <summary>
/// Gets or sets the number of daily log files to retain. /// Gets or sets the number of daily log files to retain.
/// </summary> /// </summary>
public int RetentionDays { get; set; } = 5; public int RetentionDays { get; set; } = 30;
} }
/// <summary> /// <summary>
+2 -2
View File
@@ -58,7 +58,7 @@ namespace HostAvailabilityMonitor
var logDirectory = ResolvePath(baseDirectory, config.Logging.LogDirectory); var logDirectory = ResolvePath(baseDirectory, config.Logging.LogDirectory);
var stateDirectory = ResolvePath(baseDirectory, config.Runtime.StateDirectory); var stateDirectory = ResolvePath(baseDirectory, config.Runtime.StateDirectory);
var stateFilePath = Path.Combine(stateDirectory, "monitor-state.json"); var stateFilePath = Path.Combine(stateDirectory, config.Runtime.StateFileName);
WriteConsoleInfo("Initialisiere Dateilog: " + BuildLogFilePreview(logDirectory, config.Logging.FilePrefix)); WriteConsoleInfo("Initialisiere Dateilog: " + BuildLogFilePreview(logDirectory, config.Logging.FilePrefix));
logger = new FileLogger(logDirectory, config.Logging.FilePrefix, config.Logging.RetentionDays, config.ApplicationName, config.EnvironmentName); logger = new FileLogger(logDirectory, config.Logging.FilePrefix, config.Logging.RetentionDays, config.ApplicationName, config.EnvironmentName);
@@ -699,7 +699,7 @@ namespace HostAvailabilityMonitor
try try
{ {
var directory = ResolvePath(baseDirectory ?? AppDomain.CurrentDomain.BaseDirectory, "logs"); var directory = ResolvePath(baseDirectory ?? AppDomain.CurrentDomain.BaseDirectory, "logs");
var fallbackLogger = new FileLogger(directory, "host-availability-monitor-startup", 5, "HostAvailabilityMonitor", "Startup"); var fallbackLogger = new FileLogger(directory, "host-availability-monitor-startup", 30, "HostAvailabilityMonitor", "Startup");
fallbackLogger.Error("Monitor konnte nicht gestartet werden. Konfiguration=" + (configPath ?? "(nicht aufgeloest)") + ". Fehler=" + exception.GetType().Name + ": " + exception.Message); fallbackLogger.Error("Monitor konnte nicht gestartet werden. Konfiguration=" + (configPath ?? "(nicht aufgeloest)") + ". Fehler=" + exception.GetType().Name + ": " + exception.Message);
fallbackLogger.Error("Details: " + exception); fallbackLogger.Error("Details: " + exception);
WriteConsoleInfo("Fallback-Log geschrieben: " + BuildLogFilePreview(directory, "host-availability-monitor-startup")); WriteConsoleInfo("Fallback-Log geschrieben: " + BuildLogFilePreview(directory, "host-availability-monitor-startup"));
+3 -2
View File
@@ -6,12 +6,13 @@
"DefaultValidateUncPathAccess": false, "DefaultValidateUncPathAccess": false,
"NonZeroExitCodeOnAnyFailure": false, "NonZeroExitCodeOnAnyFailure": false,
"NonZeroExitCodeOnExecutionError": true, "NonZeroExitCodeOnExecutionError": true,
"StateDirectory": "state" "StateDirectory": "state",
"StateFileName": "monitor-state.json"
}, },
"Logging": { "Logging": {
"LogDirectory": "logs", "LogDirectory": "logs",
"FilePrefix": "host-availability-monitor", "FilePrefix": "host-availability-monitor",
"RetentionDays": 5 "RetentionDays": 30
}, },
"EventLog": { "EventLog": {
"Enabled": true, "Enabled": true,