Guarantee durable visible runtime logging

This commit is contained in:
2026-08-26 10:40:29 +02:00
parent 999f69bcb9
commit fe3c84a27f
20 changed files with 520 additions and 72 deletions
@@ -39,6 +39,9 @@ namespace BizTalkPlatformManagementTool.Tests
Run("ScheduledReceivePlanCarriesAdapterMetadata", ScheduledReceivePlanCarriesAdapterMetadata);
Run("AdapterAssemblyResolverRequiresMatchingIdentity", AdapterAssemblyResolverRequiresMatchingIdentity);
Run("OperationLogPersistsCompressesAndRetainsThirtyDays", OperationLogPersistsCompressesAndRetainsThirtyDays);
Run("OperationLogUsesVerifiedStartupFallback", OperationLogUsesVerifiedStartupFallback);
Run("OperationLogFailsOverAfterAppendFailure", OperationLogFailsOverAfterAppendFailure);
Run("OperationLogSurfacesTotalStorageFailure", OperationLogSurfacesTotalStorageFailure);
Run("ExceptionDiagnosticsContainSupportContext", ExceptionDiagnosticsContainSupportContext);
Run("CsvNeutralizesFormulaValues", CsvNeutralizesFormulaValues);
Run("PackageManifestRejectsTampering", PackageManifestRejectsTampering);
@@ -244,6 +247,66 @@ namespace BizTalkPlatformManagementTool.Tests
});
}
/// <summary>Prüft, dass erst ein real beschreibbarer Pfad als aktiv gilt.</summary>
private static void OperationLogUsesVerifiedStartupFallback()
{
InTemp(directory =>
{
var blocked = Path.Combine(directory, "blocked-primary");
var fallback = Path.Combine(directory, "writable-fallback");
File.WriteAllText(blocked, "not a directory");
var logger = new OperationLogger(null, new[] { blocked, fallback });
Assert(logger.IsFileLoggingAvailable, "writable fallback was not activated");
Assert(string.Equals(logger.LogDirectory, fallback, StringComparison.OrdinalIgnoreCase), "wrong fallback directory selected");
Assert(logger.StorageWarning.Contains("Primary runtime log path is not writable"), "startup fallback warning missing");
logger.Info("verified fallback marker");
Assert(File.Exists(logger.LogFilePath), "fallback log file was not created");
Assert(File.ReadAllText(logger.LogFilePath).Contains("verified fallback marker"), "fallback append was not durable");
});
}
/// <summary>Prüft automatisches Failover, wenn der aktive Pfad später ausfällt.</summary>
private static void OperationLogFailsOverAfterAppendFailure()
{
InTemp(directory =>
{
var primary = Path.Combine(directory, "primary");
var fallback = Path.Combine(directory, "fallback");
var visible = new List<LogEntry>();
var logger = new OperationLogger(visible.Add, new[] { primary, fallback });
Assert(string.Equals(logger.LogDirectory, primary, StringComparison.OrdinalIgnoreCase), "primary directory was not initially selected");
Directory.Delete(primary, true);
File.WriteAllText(primary, "now blocked");
logger.Error("runtime failover marker");
Assert(string.Equals(logger.LogDirectory, fallback, StringComparison.OrdinalIgnoreCase), "append failure did not switch to fallback");
Assert(File.ReadAllText(logger.LogFilePath).Contains("runtime failover marker"), "failed primary record was not written to fallback");
Assert(visible.Any(x => x.Level == LogLevel.Warning && x.Message.Contains("Runtime log path switched")), "runtime fallback was not visible in the sink");
});
}
/// <summary>Prüft eine sichtbare Warnung, wenn kein Dateipfad beschreibbar ist.</summary>
private static void OperationLogSurfacesTotalStorageFailure()
{
InTemp(directory =>
{
var blockedOne = Path.Combine(directory, "blocked-one");
var blockedTwo = Path.Combine(directory, "blocked-two");
File.WriteAllText(blockedOne, "not a directory");
File.WriteAllText(blockedTwo, "not a directory");
var visible = new List<LogEntry>();
var logger = new OperationLogger(visible.Add, new[] { blockedOne, blockedTwo });
Assert(!logger.IsFileLoggingAvailable, "logger reported unavailable candidates as writable");
Assert(logger.StorageWarning.Contains("RUNTIME FILE LOGGING UNAVAILABLE"), "total startup failure diagnostic missing");
logger.Error("grid-only marker");
Assert(visible.Any(x => x.Message == "grid-only marker"), "business entry disappeared with file logging failure");
Assert(visible.Any(x => x.Level == LogLevel.Warning && x.Message.Contains("RUNTIME FILE LOGGING UNAVAILABLE")), "file logging failure was not visible in the grid sink");
});
}
/// <summary>Prüft Typ, HRESULT, innere Ausnahme und Stacktrace für Supportfälle.</summary>
private static void ExceptionDiagnosticsContainSupportContext()
{