Skip to content

Commit

Permalink
Add option to write the specified log level to standard error
Browse files Browse the repository at this point in the history
  • Loading branch information
hadashiA committed Oct 19, 2023
1 parent 79898b5 commit 22963a4
Show file tree
Hide file tree
Showing 9 changed files with 26 additions and 28 deletions.
2 changes: 1 addition & 1 deletion sandbox/ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ static async Task Main(string[] args)
{
Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", "Development");


var host = Host.CreateDefaultBuilder()
.ConfigureServices(x =>
{
Expand All @@ -174,6 +173,7 @@ static async Task Main(string[] args)
{
//options.FlushRate = TimeSpan.FromSeconds(5);

options.LogToErrorThreshold = LogLevel.Error;
#if DEBUG
options.UsePlainTextFormatter(plainText =>
{
Expand Down
20 changes: 11 additions & 9 deletions src/ZLogger/AsyncStreamLineMessageWriter.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;

namespace ZLogger
{
Expand All @@ -17,12 +13,13 @@ public class AsyncStreamLineMessageWriter : IAsyncLogProcessor, IAsyncDisposable
readonly byte newLine2;

readonly Stream stream;
readonly Stream? errorStream;
readonly Channel<IZLoggerEntry> channel;
readonly Task writeLoop;
readonly ZLoggerOptions options;
readonly CancellationTokenSource cancellationTokenSource;

public AsyncStreamLineMessageWriter(Stream stream, ZLoggerOptions options)
public AsyncStreamLineMessageWriter(Stream stream, Stream? errorStream, ZLoggerOptions options)
{
this.newLine = Encoding.UTF8.GetBytes(Environment.NewLine);
this.cancellationTokenSource = new CancellationTokenSource();
Expand All @@ -43,6 +40,7 @@ public AsyncStreamLineMessageWriter(Stream stream, ZLoggerOptions options)

this.options = options;
this.stream = stream;
this.errorStream = errorStream;
this.channel = Channel.CreateUnbounded<IZLoggerEntry>(new UnboundedChannelOptions
{
AllowSynchronousContinuations = false, // always should be in async loop.
Expand Down Expand Up @@ -86,6 +84,7 @@ void AppendLine(StreamBufferWriter writer)
async Task WriteLoop()
{
var writer = new StreamBufferWriter(stream);
var errorWriter = errorStream != null ? new StreamBufferWriter(errorStream) : null;
var formatter = options.CreateFormatter();
var reader = channel.Reader;
var sw = Stopwatch.StartNew();
Expand All @@ -99,9 +98,11 @@ async Task WriteLoop()
while (reader.TryRead(out var value))
{
info = value.LogInfo;
value.FormatUtf8(writer, formatter);
(value as IReturnableZLoggerEntry)?.Return();
AppendLine(writer);
var currentWriter = errorWriter != null && info.LogLevel >= options.LogToErrorThreshold
? errorWriter
: writer;
value.FormatUtf8(currentWriter, formatter);
AppendLine(currentWriter);
}
info = default;

Expand Down Expand Up @@ -166,6 +167,7 @@ public async ValueTask DisposeAsync()
finally
{
this.stream.Dispose();
this.errorStream?.Dispose();
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/ZLogger/Formatters/SystemTextJsonZLoggerFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Buffers;
using System.Text.Encodings.Web;
using System.Text.Json;
Expand Down
7 changes: 3 additions & 4 deletions src/ZLogger/Providers/ZLoggerConsoleLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,19 @@ public ZLoggerConsoleLoggerProvider(IOptionsMonitor<ZLoggerOptions> options)
}

public ZLoggerConsoleLoggerProvider(bool consoleOutputEncodingToUtf8, string? optionName, IOptionsMonitor<ZLoggerOptions> options)
: this(consoleOutputEncodingToUtf8, false, optionName, options)
: this(consoleOutputEncodingToUtf8, LogLevel.None, optionName, options)
{
}

public ZLoggerConsoleLoggerProvider(bool consoleOutputEncodingToUtf8, bool outputToErrorStream, string? optionName, IOptionsMonitor<ZLoggerOptions> options)
public ZLoggerConsoleLoggerProvider(bool consoleOutputEncodingToUtf8, LogLevel logToStandardErrorThreshold, string? optionName, IOptionsMonitor<ZLoggerOptions> options)
{
if (consoleOutputEncodingToUtf8)
{
Console.OutputEncoding = new UTF8Encoding(false);
}

this.options = options.Get(optionName ?? DefaultOptionName);
var stream = outputToErrorStream ? Console.OpenStandardError() : Console.OpenStandardOutput();
this.streamWriter = new AsyncStreamLineMessageWriter(stream, this.options);
this.streamWriter = new AsyncStreamLineMessageWriter(Console.OpenStandardOutput(), Console.OpenStandardError(), this.options);
}

public ILogger CreateLogger(string categoryName)
Expand Down
2 changes: 1 addition & 1 deletion src/ZLogger/Providers/ZLoggerFileLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public ZLoggerFileLoggerProvider(string filePath, string? optionName, IOptionsMo

// useAsync:false, use sync(in thread) processor, don't use FileStream buffer(use buffer size = 1).
var stream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, 1, false);
this.streamWriter = new AsyncStreamLineMessageWriter(stream, this.options);
this.streamWriter = new AsyncStreamLineMessageWriter(stream, null, this.options);
}

public ILogger CreateLogger(string categoryName)
Expand Down
2 changes: 1 addition & 1 deletion src/ZLogger/Providers/ZLoggerRollingFileLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public ZLoggerRollingFileLoggerProvider(Func<DateTimeOffset, int, string> fileNa
{
this.options = options.Get(optionName ?? DefaultOptionName);
var stream = new RollingFileStream(fileNameSelector, timestampPattern, rollSizeKB, this.options);
this.streamWriter = new AsyncStreamLineMessageWriter(stream, this.options);
this.streamWriter = new AsyncStreamLineMessageWriter(stream, null, this.options);
}

public ILogger CreateLogger(string categoryName)
Expand Down
3 changes: 1 addition & 2 deletions src/ZLogger/Providers/ZLoggerStreamLoggerProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.IO;

namespace ZLogger.Providers
{
Expand All @@ -21,7 +20,7 @@ public ZLoggerStreamLoggerProvider(Stream stream, IOptionsMonitor<ZLoggerOptions
public ZLoggerStreamLoggerProvider(Stream stream, string? optionName, IOptionsMonitor<ZLoggerOptions> options)
{
this.options = options.Get(optionName ?? DefaultOptionName);
this.streamWriter = new AsyncStreamLineMessageWriter(stream, this.options);
this.streamWriter = new AsyncStreamLineMessageWriter(stream, null, this.options);
}

public ILogger CreateLogger(string categoryName)
Expand Down
14 changes: 6 additions & 8 deletions src/ZLogger/ZLoggerLoggingBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,33 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Configuration;
using Microsoft.Extensions.Options;
using System;
using System.IO;
using System.Runtime.InteropServices;
using ZLogger.Providers;

namespace ZLogger
{
public static class ZLoggerLoggingBuilderExtensions
{
public static ILoggingBuilder AddZLoggerConsole(this ILoggingBuilder builder, bool consoleOutputEncodingToUtf8 = true, bool configureEnableAnsiEscapeCode = false, bool outputToErrorStream = false)
public static ILoggingBuilder AddZLoggerConsole(this ILoggingBuilder builder, bool consoleOutputEncodingToUtf8 = true, bool configureEnableAnsiEscapeCode = false)
{
if (configureEnableAnsiEscapeCode)
{
EnableAnsiEscapeCode();
}

builder.AddConfiguration();
builder.Services.Add(ServiceDescriptor.Singleton<ILoggerProvider, ZLoggerConsoleLoggerProvider>(x => new ZLoggerConsoleLoggerProvider(consoleOutputEncodingToUtf8, outputToErrorStream, null, x.GetRequiredService<IOptionsMonitor<ZLoggerOptions>>())));
builder.Services.Add(ServiceDescriptor.Singleton<ILoggerProvider, ZLoggerConsoleLoggerProvider>(x => new ZLoggerConsoleLoggerProvider(consoleOutputEncodingToUtf8, null, x.GetRequiredService<IOptionsMonitor<ZLoggerOptions>>())));
LoggerProviderOptions.RegisterProviderOptions<ZLoggerOptions, ZLoggerConsoleLoggerProvider>(builder.Services);

return builder;
}

public static ILoggingBuilder AddZLoggerConsole(this ILoggingBuilder builder, Action<ZLoggerOptions> configure, bool consoleOutputEncodingToUtf8 = true, bool configureEnableAnsiEscapeCode = false, bool outputToErrorStream = false)
public static ILoggingBuilder AddZLoggerConsole(this ILoggingBuilder builder, Action<ZLoggerOptions> configure, bool consoleOutputEncodingToUtf8 = true, bool configureEnableAnsiEscapeCode = false)
{
return AddZLoggerConsole(builder, ZLoggerConsoleLoggerProvider.DefaultOptionName, configure, consoleOutputEncodingToUtf8: consoleOutputEncodingToUtf8, configureEnableAnsiEscapeCode: configureEnableAnsiEscapeCode, outputToErrorStream: outputToErrorStream);
return AddZLoggerConsole(builder, ZLoggerConsoleLoggerProvider.DefaultOptionName, configure, consoleOutputEncodingToUtf8: consoleOutputEncodingToUtf8, configureEnableAnsiEscapeCode: configureEnableAnsiEscapeCode);
}

public static ILoggingBuilder AddZLoggerConsole(this ILoggingBuilder builder, string optionName, Action<ZLoggerOptions> configure, bool consoleOutputEncodingToUtf8 = true, bool configureEnableAnsiEscapeCode = false, bool outputToErrorStream = false)
public static ILoggingBuilder AddZLoggerConsole(this ILoggingBuilder builder, string optionName, Action<ZLoggerOptions> configure, bool consoleOutputEncodingToUtf8 = true, bool configureEnableAnsiEscapeCode = false)
{
if (configureEnableAnsiEscapeCode)
{
Expand All @@ -43,7 +41,7 @@ public static ILoggingBuilder AddZLoggerConsole(this ILoggingBuilder builder, st
}

builder.AddConfiguration();
builder.Services.Add(ServiceDescriptor.Singleton<ILoggerProvider, ZLoggerConsoleLoggerProvider>(x => new ZLoggerConsoleLoggerProvider(consoleOutputEncodingToUtf8, outputToErrorStream, optionName, x.GetRequiredService<IOptionsMonitor<ZLoggerOptions>>())));
builder.Services.Add(ServiceDescriptor.Singleton<ILoggerProvider, ZLoggerConsoleLoggerProvider>(x => new ZLoggerConsoleLoggerProvider(consoleOutputEncodingToUtf8, optionName, x.GetRequiredService<IOptionsMonitor<ZLoggerOptions>>())));
LoggerProviderOptions.RegisterProviderOptions<ZLoggerOptions, ZLoggerConsoleLoggerProvider>(builder.Services);

builder.Services.AddOptions<ZLoggerOptions>(optionName).Configure(configure);
Expand Down
3 changes: 2 additions & 1 deletion src/ZLogger/ZLoggerOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using Microsoft.Extensions.Logging;
using ZLogger.Formatters;

namespace ZLogger
Expand All @@ -8,6 +8,7 @@ public class ZLoggerOptions
public Action<LogInfo, Exception>? InternalErrorLogger { get; set; }
public TimeSpan? FlushRate { get; set; }
public bool IncludeScopes { get; set; }
public LogLevel LogToErrorThreshold { get; set; } = LogLevel.None;

Func<IZLoggerFormatter> formatterFactory = DefaultFormatterFactory;

Expand Down

0 comments on commit 22963a4

Please sign in to comment.