R8.XunitLogger 2.0.0

dotnet add package R8.XunitLogger --version 2.0.0
                    
NuGet\Install-Package R8.XunitLogger -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="R8.XunitLogger" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="R8.XunitLogger" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="R8.XunitLogger" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add R8.XunitLogger --version 2.0.0
                    
#r "nuget: R8.XunitLogger, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package R8.XunitLogger@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=R8.XunitLogger&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=R8.XunitLogger&version=2.0.0
                    
Install as a Cake Tool

R8.XunitLogger

Bridges Microsoft.Extensions.Logging with xUnit's ITestOutputHelper so every ILogger call in your application appears in the test runner's output window — with no boilerplate.

Supports xUnit v2 (net6.0 / netstandard2.1) and xUnit v3 (net8.0 / net10.0).

NuGet version NuGet downloads Last commit


Installation

dotnet add package R8.XunitLogger

Options

Option Type Default Description
MinimumLevel LogLevel Information Global minimum log level. Acts as the fallback when no SetMinimumLevel override or IConfiguration entry matches.
IncludeTimestamp bool true Prepend [date time] to every log line.
IncludeScopes bool false Render the active logging scope chain (=> outer => inner) before each message.
ServiceProvider IServiceProvider? null When set, log-level filtering is read from IConfiguration (Logging:LogLevel section) instead of the options above. Automatically set to the DI container's IServiceProvider when using AddXunitLogger, but you can override it with any IServiceProvider of your choice — in both unit and integration tests.
SetMinimumLevel(…) fluent chain Per-namespace level overrides. See Per-namespace levels.
Categories IList<string> Obsolete. Use SetMinimumLevel instead.

Usage

Unit tests (AddXunit)

public class UnitTest
{
    private readonly ILoggerFactory _loggerFactory;

    public UnitTest(ITestOutputHelper outputHelper)
    {
        _loggerFactory = new LoggerFactory().AddXunit(outputHelper, options =>
        {
            options.MinimumLevel = LogLevel.Debug;
            options.IncludeScopes = true;
        });
    }

    [Fact]
    public void Test()
    {
        var logger = _loggerFactory.CreateLogger<MyService>();
        // ...
    }
}

Integration tests with DI — per test (AddXunitLogger)

The test class itself implements IXunitLogProvider, so each test gets its own ITestOutputHelper wired directly:

public class IntegrationTest : IXunitLogProvider, IDisposable
{
    private readonly ITestOutputHelper _outputHelper;
    private readonly ServiceProvider _serviceProvider;

    public IntegrationTest(ITestOutputHelper outputHelper)
    {
        _outputHelper = outputHelper;
        _serviceProvider = new ServiceCollection()
            .AddLogging()
            .AddXunitLogger(message => OnWriteLine?.Invoke(message))
            .AddScoped<MyService>()
            .BuildServiceProvider();
        OnWriteLine += _outputHelper.WriteLine;
    }

    public event Action<string> OnWriteLine;

    public void Dispose() => OnWriteLine -= _outputHelper.WriteLine;

    [Fact]
    public void Test()
    {
        var svc = _serviceProvider.GetRequiredService<MyService>();
        // ...
    }
}

Integration tests with DI — shared fixture (IClassFixture)

Use this when the service container is expensive to build and should be shared across all tests in the class. The fixture implements IXunitLogProvider; each test subscribes its own ITestOutputHelper in the constructor and unsubscribes in Dispose:

// Fixture (shared across tests in the same class)
public class MyFixture : IXunitLogProvider
{
    public readonly ServiceProvider Services;

    public MyFixture()
    {
        Services = new ServiceCollection()
            .AddLogging()
            .AddXunitLogger(message => OnWriteLine?.Invoke(message), options =>
            {
                options.MinimumLevel = LogLevel.Warning;
            })
            .AddScoped<MyService>()
            .BuildServiceProvider();
    }

    public event Action<string> OnWriteLine;
}

// Test class
public class MyTests : IClassFixture<MyFixture>, IDisposable
{
    private readonly MyFixture _fixture;
    private readonly ITestOutputHelper _outputHelper;

    public MyTests(MyFixture fixture, ITestOutputHelper outputHelper)
    {
        _fixture = fixture;
        _outputHelper = outputHelper;
        _fixture.OnWriteLine += _outputHelper.WriteLine;
    }

    public void Dispose() => _fixture.OnWriteLine -= _outputHelper.WriteLine;

    [Fact]
    public void Test()
    {
        var svc = _fixture.Services.GetRequiredService<MyService>();
        // ...
    }
}

With appsettings.json / IConfiguration

Register IConfiguration in the DI container before calling AddXunitLogger. AddXunitLogger automatically wires the service provider so Logging:LogLevel entries from your configuration override MinimumLevel and SetMinimumLevel:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "MyApp.Services": "Debug"
    }
  }
}
_serviceProvider = new ServiceCollection()
    .AddSingleton<IConfiguration>(new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json")
        .Build())
    .AddLogging()
    .AddXunitLogger(message => OnWriteLine?.Invoke(message))
    .BuildServiceProvider();

Note: When using AddXunitLogger, ServiceProvider is automatically set to the DI container's own IServiceProvider. You can still override it with a custom one if needed.


Per-namespace log levels

SetMinimumLevel returns a dedicated chain object so you can stack overrides without accidentally accessing other options:

options.MinimumLevel = LogLevel.Warning;   // global default

options
    .SetMinimumLevel("MyApp",         LogLevel.Debug)    // everything in MyApp → Debug
    .SetMinimumLevel("MyApp.Data",    LogLevel.Warning)  // but Data layer → Warning
    .SetMinimumLevel("Microsoft",     LogLevel.None)     // silence Microsoft internals
    .SetMinimumLevel("System",        LogLevel.None);

The longest matching prefix wins. MinimumLevel is used when no prefix matches.


Scope rendering

Set IncludeScopes = true to render the active scope chain in Microsoft.Extensions.Logging style:

[25/04/2026 13:00:00] warn: MyApp.Services.OrderService[0]
      => Request abc-123 => ProcessOrder
      Insufficient stock for product 42

Supported scope types:

  • String: logger.BeginScope("my scope")=> my scope
  • Structured: logger.BeginScope("Order {Id}", 42)=> Order 42
  • Dictionary: logger.BeginScope(new Dictionary<string,object>{ ["OrderId"] = 42, ["CustomerId"] = "cust-99" })=> OrderId: 42 => CustomerId: cust-99
  • Nested: outer → inner rendered left-to-right

Example:

using (logger.BeginScope(new Dictionary<string, object>
       {
           ["OrderId"] = 42,
           ["CustomerId"] = "cust-99"
       }))
{
    logger.LogInformation("Processing order");
    logger.LogWarning("Stock low for order");
}

See full examples in the sample project

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 94 4/25/2026
1.1.3 2,642 2/5/2024
1.1.2 481 2/1/2024
1.1.1 473 1/1/2024
1.1.0 235 1/1/2024
1.0.0 655 10/28/2023