How Logging Is Implemented in ASP.NET Core: Architecture and Provider Deep Dive

ASP.NET Core implements logging through the Microsoft.Extensions.Logging abstraction, which uses a provider-based model where ILoggerFactory creates ILogger instances that forward messages to registered ILoggerProvider implementations configured via ILoggingBuilder during host startup.

Logging in ASP.NET Core is built on a flexible, dependency injection-driven architecture defined in the dotnet/aspnetcore repository. The implementation centers on the Microsoft.Extensions.Logging namespace, where ILoggerFactory acts as a singleton composition root that aggregates multiple logging providers as implemented in src/Logging/LoggerFactory.cs. This design allows applications to route log events to multiple destinations simultaneously while maintaining a unified programming model through constructor injection.

Core Logging Abstractions

ILogger and ILoggerFactory

The ILogger interface defines the minimal contract for writing log messages, exposing methods like LogDebug, LogInformation, and LogError. Application code typically receives an ILogger<T> via dependency injection, where the generic parameter represents the category name.

The ILoggerFactory implementation in src/Logging/LoggerFactory.cs serves as the central factory that creates ILogger instances and maintains the collection of registered providers. It is registered as a singleton in the DI container during host construction and caches logger instances by category name to optimize performance.

ILoggerProvider and the Provider Model

Providers implement ILoggerProvider to supply concrete ILogger implementations for specific output destinations. The factory aggregates all registered providers and forwards each log event to every provider that has not filtered it out. Key built-in providers include:

ILoggingBuilder Configuration

The ILoggingBuilder interface provides a fluent API for registering providers and configuring filters. The concrete implementation, LoggingBuilder in src/Components/WebAssembly/WebAssembly/src/Hosting/LoggingBuilder.cs (lines 9-17), wraps the IServiceCollection and exposes extension methods like AddConsole() and AddDebug() defined in src/Logging/LoggingBuilderExtensions.cs.

Host Integration and Service Wiring

WebApplicationBuilder.Logging Property

In modern ASP.NET Core applications, the WebApplicationBuilder exposes a Logging property that returns an ILoggingBuilder. According to the source in src/DefaultBuilder/src/WebApplicationBuilder.cs (lines 368-376), this property provides the primary entry point for configuring logging before the application starts.

Host Builder Extensions

The WebHostBuilderExtensions class in src/Hosting/Hosting/src/WebHostBuilderExtensions.cs (lines 20-28) provides the ConfigureLogging method, which allows programmatic configuration of the logging pipeline through UseStartup or direct builder configuration. These extensions forward any logging configuration supplied by the user to the DI container.

Configuring Logging in Applications

Basic configuration in Program.cs uses the ILoggingBuilder to add providers and set minimum levels:

var builder = WebApplication.CreateBuilder(args);

// Register built-in providers via ILoggingBuilder
builder.Logging.AddConsole();          // Console output
builder.Logging.AddDebug();            // Debugger output  
builder.Logging.AddEventSourceLogger(); // EventSource for Azure diagnostics

// Set global minimum level
builder.Logging.SetMinimumLevel(LogLevel.Information);

var app = builder.Build();

app.MapGet("/", (ILogger<Program> logger) => 
{
    logger.LogInformation("Request received at {Time}", DateTime.Now);
    return "Check logs";
});

app.Run();

Implementing Custom Logger Providers

Adding a custom provider requires implementing ILoggerProvider and creating an extension method for ILoggingBuilder:

public class FileLoggerProvider : ILoggerProvider
{
    private readonly string _path;
    public FileLoggerProvider(string path) => _path = path;
    
    public ILogger CreateLogger(string category) => new FileLogger(_path, category);
    public void Dispose() { }
}

public static class FileLoggerExtensions
{
    public static ILoggingBuilder AddFile(this ILoggingBuilder builder, string path) =>
        builder.Services.AddSingleton<ILoggerProvider>(new FileLoggerProvider(path));
}

Usage follows the standard pattern exposed by WebApplicationBuilder.Logging:

builder.Logging.AddFile("logs/app.log");

Using Logger Scopes for Contextual Data

Scopes provide contextual information for grouped log operations using ILogger.BeginScope:

using (_logger.BeginScope("Processing order {OrderId}", orderId))
{
    _logger.LogInformation("Validating payment");
    _logger.LogInformation("Updating inventory");
} // Scope ends here

All registered providers receive scope information. The console provider renders scope data as part of the message output, while other providers may serialize it differently according to their implementation.

Summary

  • ILoggerFactory in src/Logging/LoggerFactory.cs acts as the singleton composition root that aggregates providers and creates logger instances by category.
  • ILoggingBuilder in src/Components/WebAssembly/WebAssembly/src/Hosting/LoggingBuilder.cs wraps the service collection to enable fluent registration of providers like ConsoleLoggerProvider and DebugLoggerProvider.
  • WebApplicationBuilder.Logging in src/DefaultBuilder/src/WebApplicationBuilder.cs (lines 368-376) exposes the primary configuration entry point for minimal API applications.
  • Provider implementations handle specific output destinations, with built-in support for console, debug, and Azure App Service diagnostics.
  • The architecture supports hierarchical filtering (global, provider-specific, and category-specific) and scope propagation across all registered loggers.

Frequently Asked Questions

What is the difference between ILogger and ILoggerFactory in ASP.NET Core?

ILogger represents the writing surface that application code uses to emit log messages via methods like LogInformation and LogDebug. ILoggerFactory is the singleton factory responsible for creating ILogger instances and managing the collection of ILoggerProvider implementations. As implemented in src/Logging/LoggerFactory.cs, the factory caches loggers by category and forwards each log event to all registered providers that accept the current log level.

How do I add a custom logging provider to ASP.NET Core?

Implement ILoggerProvider to create loggers for your specific destination, then create an extension method on ILoggingBuilder that registers your provider with the service collection. The LoggingBuilder implementation in src/Components/WebAssembly/WebAssembly/src/Hosting/LoggingBuilder.cs demonstrates how these extensions wrap IServiceCollection to add providers to the DI container, making them available to the ILoggerFactory when the host builds the service provider.

Where is the minimum log level configured in ASP.NET Core?

Minimum log levels can be configured globally via ILoggingBuilder.SetMinimumLevel() or per-provider using the AddFilter method. The LoggerFactory evaluates filters hierarchically: global minimums, provider-specific settings, and category-specific rules derived from the logger's category name all determine whether a message is written to a specific provider.

How does logging work with dependency injection in ASP.NET Core?

The DI container resolves ILogger<T> by requesting it from the singleton ILoggerFactory, passing the fully qualified type name of T as the category. This occurs automatically when you include ILogger<YourClass> in your constructor, as wired through the host builder in src/DefaultBuilder/src/WebApplicationBuilder.cs. The factory creates the logger instance and binds it to all registered providers configured via builder.Logging.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →