using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace StartupHelpers; public static class EnvironmentDiagnostics { public static void LogEnvironmentSettings(ILogger logger, IConfiguration configuration, IWebHostEnvironment environment) { LogEnvironmentSettingsCore(logger, configuration, environment.ApplicationName, environment.EnvironmentName, environment.ContentRootPath, environment.WebRootPath); } public static void LogEnvironmentSettings(ILogger logger, IConfiguration configuration, IHostEnvironment environment) { LogEnvironmentSettingsCore(logger, configuration, environment.ApplicationName, environment.EnvironmentName, environment.ContentRootPath, webRootPath: null); } private static void LogEnvironmentSettingsCore( ILogger logger, IConfiguration configuration, string applicationName, string environmentName, string contentRootPath, string? webRootPath) { logger.LogInformation("==================== ENVIRONMENT SETTINGS ===================="); logger.LogInformation("Application Name: {ApplicationName}", applicationName); logger.LogInformation("Environment Name: {EnvironmentName}", environmentName); logger.LogInformation("Content Root Path: {ContentRootPath}", contentRootPath); if (!string.IsNullOrEmpty(webRootPath)) { logger.LogInformation("Web Root Path: {WebRootPath}", webRootPath); } logger.LogInformation("-------------- Environment Variables --------------"); var envVars = Environment.GetEnvironmentVariables(); var sortedEnvVars = new SortedDictionary(); foreach (System.Collections.DictionaryEntry entry in envVars) { var key = entry.Key?.ToString() ?? string.Empty; var value = entry.Value?.ToString() ?? string.Empty; if (IsSensitiveKey(key)) { value = MaskValueWithLastChars(value); } sortedEnvVars[key] = value; } foreach (var kvp in sortedEnvVars) { logger.LogInformation(" {Key} = {Value}", kvp.Key, kvp.Value); } logger.LogInformation("-------------- Configuration Settings --------------"); LogConfigurationRecursive(logger, configuration.GetChildren(), string.Empty); logger.LogInformation("==========================================================="); } private static void LogConfigurationRecursive(ILogger logger, IEnumerable sections, string prefix) { foreach (var section in sections) { var key = string.IsNullOrEmpty(prefix) ? section.Key : $"{prefix}:{section.Key}"; if (section.Value != null) { var value = section.Value; if (IsSensitiveKey(key)) { value = MaskValueWithLastChars(value); } logger.LogInformation(" {Key} = {Value}", key, value); } if (section.GetChildren().Any()) { LogConfigurationRecursive(logger, section.GetChildren(), key); } } } private static bool IsSensitiveKey(string key) { return key.Contains("Password", StringComparison.OrdinalIgnoreCase) || key.Contains("Secret", StringComparison.OrdinalIgnoreCase) || key.Contains("Token", StringComparison.OrdinalIgnoreCase) || key.Contains("Key", StringComparison.OrdinalIgnoreCase) || key.Contains("ConnectionString", StringComparison.OrdinalIgnoreCase); } private static string MaskValueWithLastChars(string value) { if (string.IsNullOrEmpty(value)) { return "***NOT SET***"; } if (value.Length <= 4) { return "***MASKED***"; } var lastChars = value[^4..]; return $"***MASKED***...{lastChars}"; } }