Skip to content

Instantly share code, notes, and snippets.

@maryamariyan
Last active May 13, 2020 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maryamariyan/22ced7ca32c88083cb16f4a8d08746e7 to your computer and use it in GitHub Desktop.
Save maryamariyan/22ced7ca32c88083cb16f4a8d08746e7 to your computer and use it in GitHub Desktop.
public class CustomConsoleLogFormatterOptions
{
public string ExtraCustomProperty { get; set; }
}
internal class CustomConsoleLogFormatterOptionsSetup : ConfigureFromConfigurationOptions<CustomConsoleLogFormatterOptions>
{
public CustomConsoleLogFormatterOptionsSetup(ILoggerProviderConfiguration<CustomConsoleLogFormatter>
providerConfiguration)
: base(providerConfiguration.Configuration)
{
}
}
public static class CustomLoggerExtensions
{
public static ILoggingBuilder AddCustomLogger(this ILoggingBuilder builder)
{
builder.AddConfiguration();
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
builder.Services.AddOptions<CustomConsoleLogFormatterOptions>().Bind(configuration.GetSection("Logging:Console"));
builder.Services.AddSingleton<ILogFormatter, CustomConsoleLogFormatter>();
builder.Services.AddSingleton<IConfigureOptions<CustomConsoleLogFormatterOptions>, CustomConsoleLogFormatterOptionsSetup>();
builder.Services.AddSingleton<IOptionsChangeTokenSource<CustomConsoleLogFormatterOptions>,
LoggerProviderOptionsChangeTokenSource<CustomConsoleLogFormatterOptions, CustomConsoleLogFormatter>>();
//builder.Services.TryAddEnumerable(
// ServiceDescriptor.Singleton<IConfigureOptions<CustomConsoleLogFormatterOptions>, CustomConsoleLogFormatterOptionsSetup>()
//);
//builder.Services.TryAddEnumerable(
// ServiceDescriptor.Singleton<IOptionsChangeTokenSource<CustomConsoleLogFormatterOptions>,
// LoggerProviderOptionsChangeTokenSource<CustomConsoleLogFormatterOptions, CustomConsoleLogFormatter>>()
//);
return builder;
}
static public ILoggingBuilder AddCustomLogger(this ILoggingBuilder builder, Action<CustomConsoleLogFormatterOptions> configure)
{
if (configure == null)
{
throw new ArgumentNullException(nameof(configure));
}
builder.AddCustomLogger();
builder.Services.Configure(configure);
return builder;
}
}
public class CustomJsonFormatter : JsonConsoleLogFormatter, IDisposable
{
public CustomJsonFormatter(IOptionsMonitor<JsonLogFormatterOptions> options) : base(options)
{ }
}
public class CustomConsoleLogFormatter : ILogFormatter, IDisposable
{
private IDisposable _optionsReloadToken;
private static readonly string _loglevelPadding = ": ";
private static readonly string _messagePadding;
private static readonly string _newLineWithMessagePadding;
[ThreadStatic]
private static StringBuilder _logBuilder;
static CustomConsoleLogFormatter()
{
var logLevelString = GetLogLevelString(LogLevel.Information);
_messagePadding = new string(' ', logLevelString.Length + _loglevelPadding.Length);
_newLineWithMessagePadding = Environment.NewLine + _messagePadding;
}
public CustomConsoleLogFormatter(IOptionsMonitor<CustomConsoleLogFormatterOptions> options)
{
FormatterOptions = options.CurrentValue;
ReloadLoggerOptions(options.CurrentValue);
_optionsReloadToken = options.OnChange(ReloadLoggerOptions);
}
public string Name => "Custom";
string WriteJson(LogLevel logLevel, string logName, int eventId, string message, Exception exception, ConsoleLoggerOptions options, IExternalScopeProvider scopeProvider)//long[] extraData)
{
const int DefaultBufferSize = 1024;
var output = new ArrayBufferWriter<byte>(DefaultBufferSize);
using (var writer = new Utf8JsonWriter(output, options.JsonWriterOptions))
{
writer.WriteStartObject();
string timestamp = null;
var timestampFormat = options.TimestampFormat;
if (timestampFormat != null)
{
var dateTime = options.UseUtcTimestamp ? DateTime.UtcNow : DateTime.Now;
timestamp = dateTime.ToString(timestampFormat);
}
writer.WriteString("timestamp", timestamp);
writer.WriteNumber("eventId", eventId);
writer.WriteString("logLevel", "InfoLevel");
writer.WriteString("category", logName);
writer.WriteString("message", message);
if (exception != null)
{
writer.WriteStartObject("Exception");
writer.WriteString("Message", exception.Message.ToString());
writer.WriteString("Type", exception.GetType().ToString());
writer.WriteStartArray("StackTrace");
foreach (var xx in exception?.StackTrace?.Split(Environment.NewLine))
{
JsonSerializer.Serialize<string>(writer, xx);
}
writer.WriteEndArray();
writer.WriteNumber("HResult", exception.HResult);
writer.WriteEndObject();
}
try
{
if (options.IncludeScopes && scopeProvider != null)
{
writer.WriteStartObject("scopes");
scopeProvider.ForEachScope((scope, state) =>
{
if (scope is IReadOnlyList<KeyValuePair<string, object>> kvps)
{
foreach (var kvp in kvps)
{
if (kvp.Value is String ss)
state.WriteString(kvp.Key, ss);
else
if (kvp.Value is int ii)
state.WriteNumber(kvp.Key, ii);
}
//state is the writer
//JsonSerializer.Serialize(state, scope);
}
}, (writer));
writer.WriteEndObject();
}
}
catch (Exception ex)
{
System.Console.WriteLine("Something went wrong" + ex.Message);
}
writer.WriteEndObject();
writer.Flush();
}
return Encoding.UTF8.GetString(output.WrittenMemory.Span);
}
public LogMessageEntry Format(LogLevel logLevel, string logName, int eventId, string message, Exception exception, ConsoleLoggerOptions options, IExternalScopeProvider scopeProvider)
{
var logBuilder = _logBuilder;
_logBuilder = null;
if (logBuilder == null)
{
logBuilder = new StringBuilder();
}
logBuilder.Append(WriteJson(logLevel, logName, eventId, message, exception, options, scopeProvider));
var formattedMessage = logBuilder.ToString();
logBuilder.Clear();
if (logBuilder.Capacity > 1024)
{
logBuilder.Capacity = 1024;
}
_logBuilder = logBuilder;
return new LogMessageEntry(
message: formattedMessage,
// timeStamp: timestamp,
// levelString: logLevelString,
levelBackground: null,
levelForeground: null,
messageColor: null,
logAsError: logLevel >= options.LogToStandardErrorThreshold,
writeCallback: console =>
{
//console.Write("XYZ", ConsoleColor.Cyan, ConsoleColor.Red);
//console.Write(FormatterOptions.ExtraCustomProperty, null, null);
// console.Write(WriteJson(), null, null);
console.Write(formattedMessage, null, null);
console.Write(Environment.NewLine, null, null);
console.Flush();
}
);
}
private DateTime GetCurrentDateTime(ConsoleLoggerOptions options)
{
return options.UseUtcTimestamp ? DateTime.UtcNow : DateTime.Now;
}
private static string GetLogLevelString(LogLevel logLevel)
{
switch (logLevel)
{
case LogLevel.Trace:
return "custom_trace";
case LogLevel.Debug:
return "custom_debug";
case LogLevel.Information:
return "custom_info";
case LogLevel.Warning:
return "custom_warn";
case LogLevel.Error:
return "custom_fail";
case LogLevel.Critical:
return "custom_critical";
default:
throw new ArgumentOutOfRangeException(nameof(logLevel));
}
}
private void GetScopeInformation(Utf8JsonWriter writer, ConsoleLoggerOptions options, IExternalScopeProvider scopeProvider)
{
try
{
if (options.IncludeScopes && scopeProvider != null)
{
writer.WriteStartArray("Scopes");
scopeProvider.ForEachScope((scope, state) =>
{
if (scope is IReadOnlyList<KeyValuePair<string, object>>)// kvps)
{
//foreach (var kvp in kvps)
//{
// //state.WritePropertyName(kvp.Key);
// JsonSerializer.Serialize(kvp.Value);
//}
//state is the writer
JsonSerializer.Serialize(state, scope);
}
}, (writer));
writer.WriteEndArray();
}
}
catch (Exception ex)
{
System.Console.WriteLine("Something went wrong" + ex.Message);
}
}
public CustomConsoleLogFormatterOptions FormatterOptions { get; set; }
private void ReloadLoggerOptions(CustomConsoleLogFormatterOptions options)
{
FormatterOptions = options;
}
public void Dispose()
{
_optionsReloadToken?.Dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment