206 lines
5.6 KiB
C#
206 lines
5.6 KiB
C#
using System.CommandLine;
|
|
|
|
using MfGames.ToolBuilder.Extensions;
|
|
|
|
using Serilog;
|
|
using Serilog.Core;
|
|
using Serilog.Events;
|
|
using Serilog.Exceptions;
|
|
using Serilog.Templates;
|
|
using Serilog.Templates.Themes;
|
|
|
|
namespace MfGames.ToolBuilder.Logging;
|
|
|
|
/// <summary>
|
|
/// A service for handling logging options.
|
|
/// </summary>
|
|
public class LoggingToolService
|
|
{
|
|
public LoggingToolService()
|
|
{
|
|
this.LogLevelOption = new Option<string>(
|
|
"--log-level",
|
|
() => nameof(LogEventLevel.Warning),
|
|
string.Format(
|
|
"Controls the verbosity of the output, not case-sensitive and prefixes allowed: {0}",
|
|
string.Join(", ", Enum.GetNames<LogEventLevel>())));
|
|
|
|
this.LogContextOption = new Option<string>(
|
|
"--log-context-format",
|
|
() => nameof(LogContextFormat.Class),
|
|
string.Format(
|
|
"Controls the format of the source context for log items, not case-sensitive and prefixes allowed: {0}",
|
|
string.Join(", ", Enum.GetNames<LogContextFormat>())));
|
|
|
|
this.LogTimeFormat = new Option<string>(
|
|
"--log-time-format",
|
|
() => "HH:mm:ss",
|
|
string.Join(
|
|
" ",
|
|
"Controls the format of the time in the log messages,",
|
|
"such as 'HH:mm:ss' (default) or 'yyyy-MM-ddTHH:mm:ss'.",
|
|
"Blank means exclude entirely."));
|
|
|
|
this.LogLevelOverrideOption = new Option<List<string>>(
|
|
"--log-level-override",
|
|
() => new List<string> { "Microsoft=Warning" },
|
|
"Overrides log levels for certain contexts in the format of either 'Context' or 'Context=Level' (repeat for multiple)")
|
|
{
|
|
Arity = ArgumentArity.OneOrMore,
|
|
};
|
|
}
|
|
|
|
public Option<string> LogContextOption { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets the common option for setting the log level.
|
|
/// </summary>
|
|
public Option<string> LogLevelOption { get; }
|
|
|
|
public Option<List<string>> LogLevelOverrideOption { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets the log time format to use.
|
|
/// </summary>
|
|
public Option<string> LogTimeFormat { get; set; }
|
|
|
|
/// <summary>
|
|
/// Adds the options to the given command.
|
|
/// </summary>
|
|
/// <param name="command"></param>
|
|
public void Attach(Command command)
|
|
{
|
|
command.AddOption(this.LogLevelOption);
|
|
command.AddOption(this.LogContextOption);
|
|
command.AddOption(this.LogTimeFormat);
|
|
command.AddOption(this.LogLevelOverrideOption);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the common options to the command.
|
|
/// </summary>
|
|
/// <param name="command"></param>
|
|
public void AttachGlobal(Command command)
|
|
{
|
|
command.AddGlobalOption(this.LogLevelOption);
|
|
command.AddGlobalOption(this.LogContextOption);
|
|
command.AddGlobalOption(this.LogTimeFormat);
|
|
command.AddGlobalOption(this.LogLevelOverrideOption);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up logging based on the global settings.
|
|
/// </summary>
|
|
/// <param name="arguments">The arguments to the command.</param>
|
|
public void Configure(string[] arguments)
|
|
{
|
|
LogEventLevel logLevel = this.GetEventLevel(arguments);
|
|
ExpressionTemplate template = this.GetExpressionTemplate(arguments);
|
|
Dictionary<string, LogEventLevel> levelOverrides =
|
|
this.GetLevelOverrides(arguments);
|
|
|
|
LoggerConfiguration configuration = new LoggerConfiguration()
|
|
.Enrich.WithDemystifiedStackTraces()
|
|
.Enrich.WithExceptionDetails()
|
|
.MinimumLevel.Is(logLevel);
|
|
|
|
foreach (KeyValuePair<string, LogEventLevel> pair in levelOverrides)
|
|
{
|
|
configuration = configuration.MinimumLevel
|
|
.Override(pair.Key, pair.Value);
|
|
}
|
|
|
|
configuration = configuration
|
|
.Enrich.FromLogContext()
|
|
.WriteTo.Console(template);
|
|
|
|
Logger logger = configuration.CreateLogger();
|
|
Log.Logger = logger;
|
|
}
|
|
|
|
private LogContextFormat GetContextFormat(string[] arguments)
|
|
{
|
|
string level = GlobalOptionHelper.GetArgumentValue(
|
|
this.LogContextOption,
|
|
arguments,
|
|
nameof(LogContextFormat.Class));
|
|
|
|
LogContextFormat format = level.GetEnumFuzzy<LogContextFormat>(
|
|
"log context format");
|
|
|
|
return format;
|
|
}
|
|
|
|
private LogEventLevel GetEventLevel(string[] arguments)
|
|
{
|
|
string level = GlobalOptionHelper.GetArgumentValue(
|
|
this.LogLevelOption,
|
|
arguments,
|
|
"Warning");
|
|
|
|
LogEventLevel logLevel = level.GetEnumFuzzy<LogEventLevel>(
|
|
"log level");
|
|
|
|
return logLevel;
|
|
}
|
|
|
|
private ExpressionTemplate GetExpressionTemplate(string[] arguments)
|
|
{
|
|
// Pull out the formats.
|
|
LogContextFormat contextFormat = this.GetContextFormat(arguments);
|
|
string timeFormat = this.GetTimeFormat(arguments);
|
|
|
|
// Figure out the expression template we want to use.
|
|
string timeExpression = string.IsNullOrWhiteSpace(timeFormat)
|
|
? ""
|
|
: $"{{@t:{timeFormat}}} ";
|
|
|
|
string contextExpression = contextFormat switch
|
|
{
|
|
LogContextFormat.None => "",
|
|
LogContextFormat.Class =>
|
|
"{#if SourceContext is not null} <{Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1)}>{#end}",
|
|
LogContextFormat.Full =>
|
|
"{#if SourceContext is not null} <{SourceContext}>{#end}",
|
|
_ => throw new ArgumentOutOfRangeException(),
|
|
};
|
|
|
|
var template = new ExpressionTemplate(
|
|
string.Join(
|
|
"",
|
|
$"[{timeExpression}{{@l:u3}}]",
|
|
contextExpression,
|
|
" {@m}\n{@x}"),
|
|
theme: TemplateTheme.Literate);
|
|
|
|
return template;
|
|
}
|
|
|
|
private Dictionary<string, LogEventLevel> GetLevelOverrides(
|
|
string[] arguments)
|
|
{
|
|
List<string> levels = GlobalOptionHelper.GetArgumentValue(
|
|
this.LogLevelOverrideOption,
|
|
arguments,
|
|
new List<string> { "Microsoft=Warning" });
|
|
|
|
return levels
|
|
.ToDictionary(
|
|
a => a.Split("=", 2)[0],
|
|
a => a.Contains("=")
|
|
? a.Split("=", 2)[1]
|
|
.GetEnumFuzzy<LogEventLevel>(
|
|
"log level")
|
|
: (LogEventLevel)int.MaxValue);
|
|
}
|
|
|
|
private string GetTimeFormat(string[] arguments)
|
|
{
|
|
string timeFormat = GlobalOptionHelper.GetArgumentValue(
|
|
this.LogTimeFormat,
|
|
arguments,
|
|
"HH:mm:ss");
|
|
return timeFormat;
|
|
}
|
|
}
|