refactor(configmanager): convert CLI to structured logging with Serilog
Replace Console.WriteLine calls with ILogger usage across all CLI commands. Serilog is configured via DI with clean message-only output suitable for CLI tooling. Log levels map to --quiet (Warning), default (Information), and --verbose (Debug) flags. - Add Serilog packages and configure in Program.cs - Convert all 7 command files to use ILoggerFactory from DI - Add BeginScope with context properties (Command, ConfigPath, etc.) - Create logging_style.md documenting patterns and best practices - Update tests with TestLoggingHelper for Serilog test configuration
This commit is contained in:
@@ -23,6 +23,7 @@ public class BackupCommandsTests
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(_backupService);
|
||||
services.AddSingleton(_autoDiscoveryService);
|
||||
services.AddTestLogging();
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
_configPathOption = new Option<string?>(["--config-path", "-c"]);
|
||||
@@ -272,10 +273,10 @@ public class BackupCommandsTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -288,7 +289,7 @@ public class BackupCommandsTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -27,6 +27,7 @@ public class ConfigCommandsTests
|
||||
services.AddSingleton(_configFileService);
|
||||
services.AddSingleton(_autoDiscoveryService);
|
||||
services.AddSingleton(_backupService);
|
||||
services.AddTestLogging();
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
_configPathOption = new Option<string?>(["--config-path", "-c"]);
|
||||
@@ -366,10 +367,10 @@ public class ConfigCommandsTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -382,7 +383,7 @@ public class ConfigCommandsTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
+17
-16
@@ -24,6 +24,7 @@ public class ConnectionCommandsTests
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(_configFileService);
|
||||
services.AddSingleton(_autoDiscoveryService);
|
||||
services.AddTestLogging();
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
_configPathOption = new Option<string?>(["--config-path", "-c"]);
|
||||
@@ -219,10 +220,10 @@ public class ConnectionCommandsTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -235,7 +236,7 @@ public class ConnectionCommandsTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -331,10 +332,10 @@ public class ConnectionCommandsTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -347,7 +348,7 @@ public class ConnectionCommandsTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -393,10 +394,10 @@ public class ConnectionCommandsTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -409,7 +410,7 @@ public class ConnectionCommandsTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -478,10 +479,10 @@ public class ConnectionCommandsTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -494,7 +495,7 @@ public class ConnectionCommandsTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -24,6 +24,7 @@ public class PipelineCommandsTests
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(_configFileService);
|
||||
services.AddSingleton(_autoDiscoveryService);
|
||||
services.AddTestLogging();
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
_configPathOption = new Option<string?>(["--config-path", "-c"]);
|
||||
|
||||
@@ -28,6 +28,7 @@ public class SecretCommandsTests
|
||||
services.AddSingleton(_configFileService);
|
||||
services.AddSingleton(_autoDiscoveryService);
|
||||
services.AddSingleton(_secureStoreManager);
|
||||
services.AddTestLogging();
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
_configPathOption = new Option<string?>(["--config-path", "-c"]);
|
||||
@@ -169,10 +170,10 @@ public class SecretCommandsTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -185,7 +186,7 @@ public class SecretCommandsTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
+5
-4
@@ -27,6 +27,7 @@ public class TestConnectionCommandTests
|
||||
services.AddSingleton(_configFileService);
|
||||
services.AddSingleton(_autoDiscoveryService);
|
||||
services.AddSingleton(_connectionTestService);
|
||||
services.AddTestLogging();
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
_configPathOption = new Option<string?>(["--config-path", "-c"]);
|
||||
@@ -243,10 +244,10 @@ public class TestConnectionCommandTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -259,7 +260,7 @@ public class TestConnectionCommandTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -31,6 +31,7 @@ public class ValidateCommandTests
|
||||
services.AddSingleton(_autoDiscoveryService);
|
||||
services.AddSingleton(_validationService);
|
||||
services.AddSingleton(_runtimeValidationService);
|
||||
services.AddTestLogging();
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
_configPathOption = new Option<string?>(["--config-path", "-c"]);
|
||||
@@ -193,10 +194,10 @@ public class ValidateCommandTests
|
||||
rootCommand.AddGlobalOption(_verboseOption);
|
||||
rootCommand.AddGlobalOption(_quietOption);
|
||||
|
||||
// Capture console error output
|
||||
var originalErr = Console.Error;
|
||||
// Capture console output (Serilog writes all output to stdout)
|
||||
var originalOut = Console.Out;
|
||||
using var writer = new StringWriter();
|
||||
Console.SetError(writer);
|
||||
Console.SetOut(writer);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -205,11 +206,11 @@ public class ValidateCommandTests
|
||||
|
||||
// Assert
|
||||
var output = writer.ToString();
|
||||
output.ShouldContain("Error");
|
||||
output.ShouldContain("Connection string 'LocalCache' is required");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetError(originalErr);
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace JdeScoping.ConfigManager.Cli.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Helper for setting up logging in CLI tests.
|
||||
/// </summary>
|
||||
public static class TestLoggingHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds Serilog logging to a service collection configured to write to Console.
|
||||
/// This allows tests to capture log output via Console.SetOut.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddTestLogging(this IServiceCollection services, LogEventLevel level = LogEventLevel.Information)
|
||||
{
|
||||
var logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Is(level)
|
||||
.WriteTo.Console(outputTemplate: "{Message:lj}{NewLine}{Exception}")
|
||||
.CreateLogger();
|
||||
|
||||
services.AddLogging(builder => builder.AddSerilog(logger, dispose: true));
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user