mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 05:18:16 +08:00
Use file scoped namespace declarations
This commit is contained in:

committed by
Phil Scott

parent
1dbaf50935
commit
ec1188b837
@ -1,34 +1,33 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Examples
|
||||
namespace Spectre.Console.Examples;
|
||||
|
||||
public class HelloCommand : Command<HelloCommand.Settings>
|
||||
{
|
||||
public class HelloCommand : Command<HelloCommand.Settings>
|
||||
private ILogger<HelloCommand> _logger;
|
||||
private IAnsiConsole _console;
|
||||
|
||||
public HelloCommand(IAnsiConsole console, ILogger<HelloCommand> logger)
|
||||
{
|
||||
private ILogger<HelloCommand> _logger;
|
||||
private IAnsiConsole _console;
|
||||
|
||||
public HelloCommand(IAnsiConsole console, ILogger<HelloCommand> logger)
|
||||
{
|
||||
_console = console;
|
||||
_logger = logger;
|
||||
_logger.LogDebug("{0} initialized", nameof(HelloCommand));
|
||||
}
|
||||
|
||||
public class Settings : LogCommandSettings
|
||||
{
|
||||
[CommandArgument(0, "[Name]")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public override int Execute(CommandContext context, Settings settings)
|
||||
{
|
||||
_logger.LogInformation("Starting my command");
|
||||
AnsiConsole.MarkupLine($"Hello, [blue]{settings.Name}[/]");
|
||||
_logger.LogInformation("Completed my command");
|
||||
|
||||
return 0;
|
||||
}
|
||||
_console = console;
|
||||
_logger = logger;
|
||||
_logger.LogDebug("{0} initialized", nameof(HelloCommand));
|
||||
}
|
||||
}
|
||||
|
||||
public class Settings : LogCommandSettings
|
||||
{
|
||||
[CommandArgument(0, "[Name]")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public override int Execute(CommandContext context, Settings settings)
|
||||
{
|
||||
_logger.LogInformation("Starting my command");
|
||||
AnsiConsole.MarkupLine($"Hello, [blue]{settings.Name}[/]");
|
||||
_logger.LogInformation("Completed my command");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -5,28 +5,28 @@ using System.Globalization;
|
||||
using Serilog.Events;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Examples
|
||||
namespace Spectre.Console.Examples;
|
||||
|
||||
public class LogCommandSettings : CommandSettings
|
||||
{
|
||||
public class LogCommandSettings : CommandSettings
|
||||
[CommandOption("--logFile")]
|
||||
[Description("Path and file name for logging")]
|
||||
public string LogFile { get; set; }
|
||||
|
||||
[CommandOption("--logLevel")]
|
||||
[Description("Minimum level for logging")]
|
||||
[TypeConverter(typeof(VerbosityConverter))]
|
||||
[DefaultValue(LogEventLevel.Information)]
|
||||
public LogEventLevel LogLevel { get; set; }
|
||||
}
|
||||
|
||||
public sealed class VerbosityConverter : TypeConverter
|
||||
{
|
||||
private readonly Dictionary<string, LogEventLevel> _lookup;
|
||||
|
||||
public VerbosityConverter()
|
||||
{
|
||||
[CommandOption("--logFile")]
|
||||
[Description("Path and file name for logging")]
|
||||
public string LogFile { get; set; }
|
||||
|
||||
[CommandOption("--logLevel")]
|
||||
[Description("Minimum level for logging")]
|
||||
[TypeConverter(typeof(VerbosityConverter))]
|
||||
[DefaultValue(LogEventLevel.Information)]
|
||||
public LogEventLevel LogLevel { get; set; }
|
||||
}
|
||||
|
||||
public sealed class VerbosityConverter : TypeConverter
|
||||
{
|
||||
private readonly Dictionary<string, LogEventLevel> _lookup;
|
||||
|
||||
public VerbosityConverter()
|
||||
{
|
||||
_lookup = new Dictionary<string, LogEventLevel>(StringComparer.OrdinalIgnoreCase)
|
||||
_lookup = new Dictionary<string, LogEventLevel>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{"d", LogEventLevel.Debug},
|
||||
{"v", LogEventLevel.Verbose},
|
||||
@ -35,22 +35,21 @@ namespace Spectre.Console.Examples
|
||||
{"e", LogEventLevel.Error},
|
||||
{"f", LogEventLevel.Fatal}
|
||||
};
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string stringValue)
|
||||
{
|
||||
var result = _lookup.TryGetValue(stringValue, out var verbosity);
|
||||
if (!result)
|
||||
{
|
||||
const string format = "The value '{0}' is not a valid verbosity.";
|
||||
var message = string.Format(CultureInfo.InvariantCulture, format, value);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
return verbosity;
|
||||
}
|
||||
throw new NotSupportedException("Can't convert value to verbosity.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string stringValue)
|
||||
{
|
||||
var result = _lookup.TryGetValue(stringValue, out var verbosity);
|
||||
if (!result)
|
||||
{
|
||||
const string format = "The value '{0}' is not a valid verbosity.";
|
||||
var message = string.Format(CultureInfo.InvariantCulture, format, value);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
return verbosity;
|
||||
}
|
||||
throw new NotSupportedException("Can't convert value to verbosity.");
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,18 @@
|
||||
using Serilog.Core;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Examples
|
||||
{
|
||||
public class LogInterceptor : ICommandInterceptor
|
||||
{
|
||||
public static readonly LoggingLevelSwitch LogLevel = new();
|
||||
namespace Spectre.Console.Examples;
|
||||
|
||||
public void Intercept(CommandContext context, CommandSettings settings)
|
||||
public class LogInterceptor : ICommandInterceptor
|
||||
{
|
||||
public static readonly LoggingLevelSwitch LogLevel = new();
|
||||
|
||||
public void Intercept(CommandContext context, CommandSettings settings)
|
||||
{
|
||||
if (settings is LogCommandSettings logSettings)
|
||||
{
|
||||
if (settings is LogCommandSettings logSettings)
|
||||
{
|
||||
LoggingEnricher.Path = logSettings.LogFile ?? "application.log";
|
||||
LogLevel.MinimumLevel = logSettings.LogLevel;
|
||||
}
|
||||
LoggingEnricher.Path = logSettings.LogFile ?? "application.log";
|
||||
LogLevel.MinimumLevel = logSettings.LogLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,38 +1,37 @@
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Spectre.Console.Examples
|
||||
namespace Spectre.Console.Examples;
|
||||
|
||||
internal class LoggingEnricher : ILogEventEnricher
|
||||
{
|
||||
internal class LoggingEnricher : ILogEventEnricher
|
||||
private string _cachedLogFilePath;
|
||||
private LogEventProperty _cachedLogFilePathProperty;
|
||||
|
||||
// this path and level will be set by the LogInterceptor.cs after parsing the settings
|
||||
public static string Path = string.Empty;
|
||||
|
||||
public const string LogFilePathPropertyName = "LogFilePath";
|
||||
|
||||
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
|
||||
{
|
||||
private string _cachedLogFilePath;
|
||||
private LogEventProperty _cachedLogFilePathProperty;
|
||||
// the settings might not have a path or we might not be within a command in which case
|
||||
// we won't have the setting so a default value for the log file will be required
|
||||
LogEventProperty logFilePathProperty;
|
||||
|
||||
// this path and level will be set by the LogInterceptor.cs after parsing the settings
|
||||
public static string Path = string.Empty;
|
||||
|
||||
public const string LogFilePathPropertyName = "LogFilePath";
|
||||
|
||||
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
|
||||
if (_cachedLogFilePathProperty != null && Path.Equals(_cachedLogFilePath))
|
||||
{
|
||||
// the settings might not have a path or we might not be within a command in which case
|
||||
// we won't have the setting so a default value for the log file will be required
|
||||
LogEventProperty logFilePathProperty;
|
||||
|
||||
if (_cachedLogFilePathProperty != null && Path.Equals(_cachedLogFilePath))
|
||||
{
|
||||
// Path hasn't changed, so let's use the cached property
|
||||
logFilePathProperty = _cachedLogFilePathProperty;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We've got a new path for the log. Let's create a new property
|
||||
// and cache it for future log events to use
|
||||
_cachedLogFilePath = Path;
|
||||
_cachedLogFilePathProperty = logFilePathProperty = propertyFactory.CreateProperty(LogFilePathPropertyName, Path);
|
||||
}
|
||||
|
||||
logEvent.AddPropertyIfAbsent(logFilePathProperty);
|
||||
// Path hasn't changed, so let's use the cached property
|
||||
logFilePathProperty = _cachedLogFilePathProperty;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We've got a new path for the log. Let's create a new property
|
||||
// and cache it for future log events to use
|
||||
_cachedLogFilePath = Path;
|
||||
_cachedLogFilePathProperty = logFilePathProperty = propertyFactory.CreateProperty(LogFilePathPropertyName, Path);
|
||||
}
|
||||
|
||||
logEvent.AddPropertyIfAbsent(logFilePathProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,40 +2,39 @@ using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Examples
|
||||
namespace Spectre.Console.Examples;
|
||||
|
||||
public sealed class TypeRegistrar : ITypeRegistrar
|
||||
{
|
||||
public sealed class TypeRegistrar : ITypeRegistrar
|
||||
private readonly IServiceCollection _builder;
|
||||
|
||||
public TypeRegistrar(IServiceCollection builder)
|
||||
{
|
||||
private readonly IServiceCollection _builder;
|
||||
|
||||
public TypeRegistrar(IServiceCollection builder)
|
||||
{
|
||||
_builder = builder;
|
||||
}
|
||||
|
||||
public ITypeResolver Build()
|
||||
{
|
||||
return new TypeResolver(_builder.BuildServiceProvider());
|
||||
}
|
||||
|
||||
public void Register(Type service, Type implementation)
|
||||
{
|
||||
_builder.AddSingleton(service, implementation);
|
||||
}
|
||||
|
||||
public void RegisterInstance(Type service, object implementation)
|
||||
{
|
||||
_builder.AddSingleton(service, implementation);
|
||||
}
|
||||
|
||||
public void RegisterLazy(Type service, Func<object> func)
|
||||
{
|
||||
if (func is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(func));
|
||||
}
|
||||
|
||||
_builder.AddSingleton(service, _ => func());
|
||||
}
|
||||
_builder = builder;
|
||||
}
|
||||
}
|
||||
|
||||
public ITypeResolver Build()
|
||||
{
|
||||
return new TypeResolver(_builder.BuildServiceProvider());
|
||||
}
|
||||
|
||||
public void Register(Type service, Type implementation)
|
||||
{
|
||||
_builder.AddSingleton(service, implementation);
|
||||
}
|
||||
|
||||
public void RegisterInstance(Type service, object implementation)
|
||||
{
|
||||
_builder.AddSingleton(service, implementation);
|
||||
}
|
||||
|
||||
public void RegisterLazy(Type service, Func<object> func)
|
||||
{
|
||||
if (func is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(func));
|
||||
}
|
||||
|
||||
_builder.AddSingleton(service, _ => func());
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,19 @@ using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace Spectre.Console.Examples
|
||||
namespace Spectre.Console.Examples;
|
||||
|
||||
public sealed class TypeResolver : ITypeResolver
|
||||
{
|
||||
public sealed class TypeResolver : ITypeResolver
|
||||
private readonly IServiceProvider _provider;
|
||||
|
||||
public TypeResolver(IServiceProvider provider)
|
||||
{
|
||||
private readonly IServiceProvider _provider;
|
||||
|
||||
public TypeResolver(IServiceProvider provider)
|
||||
{
|
||||
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
||||
}
|
||||
|
||||
public object Resolve(Type type)
|
||||
{
|
||||
return _provider.GetRequiredService(type);
|
||||
}
|
||||
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
||||
}
|
||||
}
|
||||
|
||||
public object Resolve(Type type)
|
||||
{
|
||||
return _provider.GetRequiredService(type);
|
||||
}
|
||||
}
|
||||
|
@ -12,42 +12,41 @@ using Spectre.Console.Cli;
|
||||
* Spectre.Console CommandInterceptor
|
||||
*/
|
||||
|
||||
namespace Spectre.Console.Examples
|
||||
namespace Spectre.Console.Examples;
|
||||
|
||||
public class Program
|
||||
{
|
||||
public class Program
|
||||
static int Main(string[] args)
|
||||
{
|
||||
static int Main(string[] args)
|
||||
// to retrieve the log file name, we must first parse the command settings
|
||||
// this will require us to delay setting the file path for the file writer.
|
||||
// With serilog we can use an enricher and Serilog.Sinks.Map to dynamically
|
||||
// pull this setting.
|
||||
var serviceCollection = new ServiceCollection()
|
||||
.AddLogging(configure =>
|
||||
configure.AddSerilog(new LoggerConfiguration()
|
||||
// log level will be dynamically be controlled by our log interceptor upon running
|
||||
.MinimumLevel.ControlledBy(LogInterceptor.LogLevel)
|
||||
// the log enricher will add a new property with the log file path from the settings
|
||||
// that we can use to set the path dynamically
|
||||
.Enrich.With<LoggingEnricher>()
|
||||
// serilog.sinks.map will defer the configuration of the sink to be ondemand
|
||||
// allowing us to look at the properties set by the enricher to set the path appropriately
|
||||
.WriteTo.Map(LoggingEnricher.LogFilePathPropertyName,
|
||||
(logFilePath, wt) => wt.File($"{logFilePath}"), 1)
|
||||
.CreateLogger()
|
||||
)
|
||||
);
|
||||
|
||||
var registrar = new TypeRegistrar(serviceCollection);
|
||||
var app = new CommandApp(registrar);
|
||||
|
||||
app.Configure(config =>
|
||||
{
|
||||
// to retrieve the log file name, we must first parse the command settings
|
||||
// this will require us to delay setting the file path for the file writer.
|
||||
// With serilog we can use an enricher and Serilog.Sinks.Map to dynamically
|
||||
// pull this setting.
|
||||
var serviceCollection = new ServiceCollection()
|
||||
.AddLogging(configure =>
|
||||
configure.AddSerilog(new LoggerConfiguration()
|
||||
// log level will be dynamically be controlled by our log interceptor upon running
|
||||
.MinimumLevel.ControlledBy(LogInterceptor.LogLevel)
|
||||
// the log enricher will add a new property with the log file path from the settings
|
||||
// that we can use to set the path dynamically
|
||||
.Enrich.With<LoggingEnricher>()
|
||||
// serilog.sinks.map will defer the configuration of the sink to be ondemand
|
||||
// allowing us to look at the properties set by the enricher to set the path appropriately
|
||||
.WriteTo.Map(LoggingEnricher.LogFilePathPropertyName,
|
||||
(logFilePath, wt) => wt.File($"{logFilePath}"), 1)
|
||||
.CreateLogger()
|
||||
)
|
||||
);
|
||||
|
||||
var registrar = new TypeRegistrar(serviceCollection);
|
||||
var app = new CommandApp(registrar);
|
||||
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.SetInterceptor(new LogInterceptor()); // add the interceptor
|
||||
config.SetInterceptor(new LogInterceptor()); // add the interceptor
|
||||
config.AddCommand<HelloCommand>("hello");
|
||||
});
|
||||
});
|
||||
|
||||
return app.Run(args);
|
||||
}
|
||||
return app.Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user