diff --git a/Documentation.en.md b/Documentation.en.md
index 4ab167a..087b105 100644
--- a/Documentation.en.md
+++ b/Documentation.en.md
@@ -145,6 +145,25 @@ File: `src\HostAvailabilityMonitor\appsettings.json`
- `HipVirtualMachines`: optional static VM checks
- `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
Important fields in `Email`:
@@ -330,12 +349,13 @@ It contains:
- `Logging`
- `EventLog`
- `Email`
+- `HipVirtualMachines`
`Targets` is rebuilt by the generator at runtime.
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:
- daily rolling logs
-- default retention of 5 days
+- default retention of 30 days, configurable through `Logging.RetentionDays`
- event log writes are best effort only
- state file is written atomically
- failure/recovery emails follow explicit notification rules
diff --git a/Dokumentation.md b/Dokumentation.md
index 5f78240..8b343da 100644
--- a/Dokumentation.md
+++ b/Dokumentation.md
@@ -145,6 +145,25 @@ Datei: `src\HostAvailabilityMonitor\appsettings.json`
- `HipVirtualMachines`: optionale statische VM-Prüfungen
- `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
Wichtige Felder im Abschnitt `Email`:
@@ -330,12 +349,13 @@ Hier werden gepflegt:
- `Logging`
- `EventLog`
- `Email`
+- `HipVirtualMachines`
`Targets` wird vom Generator zur Laufzeit neu erzeugt.
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:
- 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
- Statusdatei mit atomischem Schreiben
- Failure-/Recovery-Mails nur bei definierten Bedingungen
diff --git a/README.md b/README.md
index 6017b42..1fc5c7d 100644
--- a/README.md
+++ b/README.md
@@ -86,7 +86,7 @@ Diese Struktur ist bewusst einfach gehalten, damit das Repository sauber in **Gi
- Task-Scheduler-tauglich
- tägliche Logrotation
-- Log-Retention standardmäßig 5 Tage
+- Log-Retention standardmäßig 30 Tage
- Windows Application Event Log
- 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
@@ -341,6 +341,8 @@ Wichtige Felder:
- `BizTalk.ApplicationMappings`: Mapping von BizTalk-Anwendungsnamen auf fachliche App-Namen
- `Output.Path`: Pfad der zu erzeugenden Monitor-JSON
- `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.Email.SendDailySummary`: tägliche Status-Mail in der generierten Monitor-JSON einschalten
- `GeneratedMonitorConfig.Email.DailySummaryHourLocal`: lokale Uhrzeit der Tageszusammenfassung
diff --git a/src/BizTalkMonitorConfigGenerator/Configuration/GeneratorConfiguration.cs b/src/BizTalkMonitorConfigGenerator/Configuration/GeneratorConfiguration.cs
index d528d20..a7ecf9c 100644
--- a/src/BizTalkMonitorConfigGenerator/Configuration/GeneratorConfiguration.cs
+++ b/src/BizTalkMonitorConfigGenerator/Configuration/GeneratorConfiguration.cs
@@ -213,7 +213,7 @@ namespace BizTalkMonitorConfigGenerator.Configuration
///
/// Gets or sets the number of daily generator log files to retain.
///
- public int RetentionDays { get; set; } = 5;
+ public int RetentionDays { get; set; } = 30;
}
///
@@ -424,6 +424,23 @@ namespace BizTalkMonitorConfigGenerator.Configuration
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)
{
throw new InvalidOperationException("GeneratedMonitorConfig.Logging.RetentionDays darf nicht negativ sein.");
@@ -493,7 +510,8 @@ namespace BizTalkMonitorConfigGenerator.Configuration
DefaultValidateUncPathAccess = configuration.Runtime.DefaultValidateUncPathAccess,
NonZeroExitCodeOnAnyFailure = configuration.Runtime.NonZeroExitCodeOnAnyFailure,
NonZeroExitCodeOnExecutionError = configuration.Runtime.NonZeroExitCodeOnExecutionError,
- StateDirectory = configuration.Runtime.StateDirectory
+ StateDirectory = configuration.Runtime.StateDirectory,
+ StateFileName = configuration.Runtime.StateFileName
},
Logging = new LoggingOptions
{
diff --git a/src/BizTalkMonitorConfigGenerator/Program.cs b/src/BizTalkMonitorConfigGenerator/Program.cs
index c2b2596..5db5fdc 100644
--- a/src/BizTalkMonitorConfigGenerator/Program.cs
+++ b/src/BizTalkMonitorConfigGenerator/Program.cs
@@ -241,7 +241,7 @@ namespace BizTalkMonitorConfigGenerator
try
{
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("Details: " + exception);
WriteConsoleInfo("Fallback-Log geschrieben: " + BuildLogFilePreview(directory, "biztalk-monitor-config-generator-startup"));
diff --git a/src/BizTalkMonitorConfigGenerator/generator-settings.json b/src/BizTalkMonitorConfigGenerator/generator-settings.json
index 0d1e383..48fb7bd 100644
--- a/src/BizTalkMonitorConfigGenerator/generator-settings.json
+++ b/src/BizTalkMonitorConfigGenerator/generator-settings.json
@@ -4,7 +4,7 @@
"Logging": {
"LogDirectory": "logs",
"FilePrefix": "biztalk-monitor-config-generator",
- "RetentionDays": 5
+ "RetentionDays": 30
},
"EventLog": {
"Enabled": true,
@@ -52,12 +52,13 @@
"DefaultValidateUncPathAccess": false,
"NonZeroExitCodeOnAnyFailure": false,
"NonZeroExitCodeOnExecutionError": true,
- "StateDirectory": "state"
+ "StateDirectory": "state",
+ "StateFileName": "monitor-state.json"
},
"Logging": {
"LogDirectory": "logs",
"FilePrefix": "host-availability-monitor",
- "RetentionDays": 5
+ "RetentionDays": 30
},
"EventLog": {
"Enabled": true,
diff --git a/src/HostAvailabilityMonitor/Configuration/MonitorConfiguration.cs b/src/HostAvailabilityMonitor/Configuration/MonitorConfiguration.cs
index 45f9551..7e2b73d 100644
--- a/src/HostAvailabilityMonitor/Configuration/MonitorConfiguration.cs
+++ b/src/HostAvailabilityMonitor/Configuration/MonitorConfiguration.cs
@@ -158,6 +158,23 @@ namespace HostAvailabilityMonitor.Configuration
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)
{
HipVirtualMachines = new HipVirtualMachineOptions();
@@ -286,6 +303,11 @@ namespace HostAvailabilityMonitor.Configuration
/// Gets or sets the state directory path.
///
public string StateDirectory { get; set; } = "state";
+
+ ///
+ /// Gets or sets the state file name inside the configured state directory.
+ ///
+ public string StateFileName { get; set; } = "monitor-state.json";
}
///
@@ -306,7 +328,7 @@ namespace HostAvailabilityMonitor.Configuration
///
/// Gets or sets the number of daily log files to retain.
///
- public int RetentionDays { get; set; } = 5;
+ public int RetentionDays { get; set; } = 30;
}
///
diff --git a/src/HostAvailabilityMonitor/Program.cs b/src/HostAvailabilityMonitor/Program.cs
index 97dd506..6dd551a 100644
--- a/src/HostAvailabilityMonitor/Program.cs
+++ b/src/HostAvailabilityMonitor/Program.cs
@@ -58,7 +58,7 @@ namespace HostAvailabilityMonitor
var logDirectory = ResolvePath(baseDirectory, config.Logging.LogDirectory);
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));
logger = new FileLogger(logDirectory, config.Logging.FilePrefix, config.Logging.RetentionDays, config.ApplicationName, config.EnvironmentName);
@@ -699,7 +699,7 @@ namespace HostAvailabilityMonitor
try
{
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("Details: " + exception);
WriteConsoleInfo("Fallback-Log geschrieben: " + BuildLogFilePreview(directory, "host-availability-monitor-startup"));
diff --git a/src/HostAvailabilityMonitor/appsettings.json b/src/HostAvailabilityMonitor/appsettings.json
index 1340d8d..2a3f198 100644
--- a/src/HostAvailabilityMonitor/appsettings.json
+++ b/src/HostAvailabilityMonitor/appsettings.json
@@ -6,12 +6,13 @@
"DefaultValidateUncPathAccess": false,
"NonZeroExitCodeOnAnyFailure": false,
"NonZeroExitCodeOnExecutionError": true,
- "StateDirectory": "state"
+ "StateDirectory": "state",
+ "StateFileName": "monitor-state.json"
},
"Logging": {
"LogDirectory": "logs",
"FilePrefix": "host-availability-monitor",
- "RetentionDays": 5
+ "RetentionDays": 30
},
"EventLog": {
"Enabled": true,