Skip to content

Instantly share code, notes, and snippets.

@benbrandt22
Created March 1, 2023 19:20
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 benbrandt22/2ac71eeed151388ef606820bc7606fe7 to your computer and use it in GitHub Desktop.
Save benbrandt22/2ac71eeed151388ef606820bc7606fe7 to your computer and use it in GitHub Desktop.
ILogger / ILoggerFactory implementation to use in XUnit tests for pushing log messages into the test output
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit.Abstractions;
namespace MyGists;
public class TestOutputLoggerFactory : ILoggerFactory
{
private readonly ITestOutputHelper _testOutputHelper;
public TestOutputLoggerFactory(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}
/// <summary>
/// Registers a logger that outputs to the unit test output, to easily display logging messages in unit test results.
/// </summary>
public static void Register(IServiceCollection serviceCollection, ITestOutputHelper testOutputHelper)
=> serviceCollection.AddTransient<ILoggerFactory>(provider => new TestOutputLoggerFactory(testOutputHelper));
public void Dispose() { }
public ILogger CreateLogger(string categoryName) => TestOutputLogger.CreateLogger(_testOutputHelper, categoryName);
public void AddProvider(ILoggerProvider provider)
{
throw new NotImplementedException();
}
}
public class TestOutputLogger : ILogger
{
private readonly ITestOutputHelper _testOutputHelper;
private readonly LoggerExternalScopeProvider _scopeProvider;
private readonly string _categoryName;
public TestOutputLogger(ITestOutputHelper testOutputHelper, LoggerExternalScopeProvider scopeProvider, string categoryName)
{
_testOutputHelper = testOutputHelper;
_scopeProvider = scopeProvider;
_categoryName = categoryName;
}
public static ILogger CreateLogger(ITestOutputHelper testOutputHelper, string categoryName) => new TestOutputLogger(testOutputHelper, new LoggerExternalScopeProvider(), categoryName);
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
var sb = new StringBuilder();
sb.Append(GetLogLevelString(logLevel))
.Append(" [").Append(_categoryName).Append("] ")
.Append(formatter(state, exception));
if (exception != null)
{
sb.Append('\n').Append(exception);
}
_scopeProvider.ForEachScope((scope, s) =>
{
s.Append("\n => ");
s.Append(scope);
}, sb);
_testOutputHelper.WriteLine(sb.ToString());
}
private static string GetLogLevelString(LogLevel logLevel) =>
logLevel switch
{
LogLevel.Trace => "TRACE",
LogLevel.Debug => "DEBUG",
LogLevel.Information => "INFO ",
LogLevel.Warning => "WARN ",
LogLevel.Error => "ERROR",
LogLevel.Critical => "CRIT ",
_ => throw new ArgumentOutOfRangeException(nameof(logLevel))
};
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => _scopeProvider.Push(state);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment