Skip to content

Aspnet Logging

DodaTech 4 min read

title: ASP.NET Core Logging — Complete Guide to Application Logging description: 'Learn ASP.NET Core logging: ILogger interface, log levels, structured logging, Serilog, log providers, filtering, and best practices for production logging.' date: 2026-06-28 lastmod: 2026-06-28 weight: 30 tags: [backend, aspnet]


ASP.NET Core logging provides a built-in abstraction through ILogger, supporting structured logging, multiple providers (Console, Debug, EventLog), and third-party libraries like Serilog.

## What You'll Learn

By the end of this tutorial, you'll use ILogger for structured logging, configure log levels per category, integrate Serilog for file/JSON logging, filter sensitive data, and implement best practices.

## Real-World Use

A production API logs all requests with CorrelationId, user ID, and response time. Errors are sent to Elasticsearch via Serilog. The operations team monitors dashboards in Kibana.

## Logging Learning Path

```mermaid
flowchart LR
  A[Testing] --> B[Logging]
  B --> C[Health Checks]
  C --> D[Docker]
  D --> E[Deployment]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Basic Logging

public class ProductsController : ControllerBase
{
    private readonly ILogger<ProductsController> _logger;
    public ProductsController(ILogger<ProductsController> logger) => _logger = logger;
    
    [HttpGet("{id}")]
    public async Task<ActionResult<Product>> GetById(int id)
    {
        _logger.LogInformation("Fetching product {ProductId}", id);
        try
        {
            var product = await _service.GetByIdAsync(id);
            if (product == null)
            {
                _logger.LogWarning("Product {ProductId} not found", id);
                return NotFound();
            }
            return Ok(product);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error fetching product {ProductId}", id);
            throw;
        }
    }
}

Configuration

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.AspNetCore": "Warning",
      "MyApp": "Debug"
    },
    "Console": {
      "LogLevel": {
        "MyApp.Services": "Information"
      }
    }
  }
}
// Program.cs
builder.Logging.ClearProviders();           // Remove default providers
builder.Logging.AddConsole();                // Add console
builder.Logging.AddDebug();                  // Add debug (VS Output)
builder.Logging.AddEventLog();               // Windows Event Log
builder.Logging.AddFilter("Microsoft", LogLevel.Warning);  // Filter

Serilog Setup

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.File
dotnet add package Serilog.Sinks.Seq
using Serilog;
// Configure early (before building app)
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}")
    .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day)
    .WriteTo.Seq("http://localhost:5341")
    .Enrich.WithCorrelationId()
    .CreateLogger();
builder.Host.UseSerilog();

// Or configure via appsettings.json
// "Serilog": {
//   "MinimumLevel": { "Default": "Information" },
//   "WriteTo": [
//     { "Name": "Console" },
//     { "Name": "File", "Args": { "path": "logs/app-.log", "rollingInterval": "Day" } }
//   ]
// }

Structured Logging

// Bad - string concatenation
_logger.LogInformation("User " + userId + " logged in from " + ip);

// Good - structured (searchable)
_logger.LogInformation("User {UserId} logged in from {IpAddress}", userId, ip);

// With custom properties
using (_logger.BeginScope(new Dictionary<string, object>
{
    ["CorrelationId"] = httpContext.TraceIdentifier,
    ["UserId"] = userId
}))
{
    _logger.LogInformation("Processing order {OrderId}", orderId);
    // All logs in this scope include CorrelationId and UserId
}

Common Mistakes

1. String Interpolation in Logs

LogInterpolatedStringHandler may cause issues. Use structured placeholders {Name} instead of string interpolation.

2. Logging Exceptions Incorrectly

Always pass the exception as the first parameter: _logger.LogError(ex, "Message"). Don't log ex.ToString() in the message.

3. Too Much Logging in Hot Paths

Logging in performance-critical code (tight loops) slows the app. Log at higher levels or reduce frequency.

4. Logging Sensitive Data

Credit cards, passwords, and PII in logs create security risks. Use destructuring policies to mask sensitive fields.

5. Using Console.WriteLine in Production

Use ILogger everywhere. Console.WriteLine doesn't create structured logs and can't be filtered.

Practice Questions

1. What is structured logging?

Logging with named placeholders ({UserId}) instead of concatenation. Enables searchable, queryable logs.

2. How do you configure different log levels per category?

In appsettings.json: set LogLevel per namespace (Microsoft.AspNetCore: Warning, MyApp: Debug).

3. What is Serilog?

A popular third-party logging library for .NET with sinks to files, databases, Elasticsearch, Seq, and more.

4. How do you filter logs by level?

Set MinimumLevel or use AddFilter to suppress verbose logs from specific categories.

5. Challenge: Configure Serilog with console and file sinks, and structured logging.

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Console()
    .WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();
builder.Host.UseSerilog();

FAQ

What is the difference between LogInformation and LogDebug?

Information logs normal operations. Debug logs detailed diagnostic info (only in development).

Should I use the built-in logging or Serilog?

Built-in works for simple apps. Serilog is better for structured logging, multiple sinks, and production monitoring.

How do I log to multiple destinations?

Add multiple providers/write-to sinks. Each provider receives logs independently.

What is Seq?

A centralized log server that accepts structured logs via HTTP. Search, filter, and dashboard logs.

How do I mask sensitive data in logs?

Use Serilog's destructuring: .Destructure.With() or .Destructure.ByTransforming(u => new { u.Id, u.Name })

Mini Project: Structured Logging with Serilog

Configure a complete logging pipeline with Serilog, console, file, and structured output.

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning)
    .WriteTo.Console()
    .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7)
    .Enrich.WithMachineName()
    .Enrich.WithThreadId()
    .CreateLogger();
try {
    var app = builder.Build();
    app.UseSerilogRequestLogging();  // Log all HTTP requests
    app.Run();
} finally { Log.CloseAndFlush(); }

What's Next

ASP.NET Core Health Checks ASP.NET Core Docker

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro