Skip to content

Logging in C# — Complete Guide

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Logging in C#. We cover key concepts, practical examples, and best practices to help you master this topic.

Hook

Logging is the eyes and ears of your application in production. When something goes wrong at 3 AM, well-structured logs are often the only tool you have to diagnose the issue. C# applications benefit from a mature logging ecosystem built on Microsoft.Extensions.Logging.

Learning Path

graph LR
  A[Logging] --> B[ILogger]
  A --> C[Log Levels]
  B --> D[Providers]
  B --> E[Structured Logging]
  D --> F[Serilog NLog]
  style A fill:#4a90d9,color:#fff
  style B fill:#4a90d9,color:#fff
  style C fill:#4a90d9,color:#fff
  style D fill:#4a90d9,color:#fff
  style E fill:#4a90d9,color:#fff
  style F fill:#4a90d9,color:#fff

ILogger Basics

The ILogger<T> interface from Microsoft.Extensions.Logging is the standard logging abstraction in .NET.

using Microsoft.Extensions.Logging;

public class OrderProcessor
{
    private readonly ILogger<OrderProcessor> _logger;

    public OrderProcessor(ILogger<OrderProcessor> logger)
    {
        _logger = logger;
    }

    public void ProcessOrder(int orderId)
    {
        _logger.LogInformation("Processing order {OrderId}", orderId);

        try
        {
            // Business logic
            _logger.LogDebug("Order {OrderId} processed successfully", orderId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to process order {OrderId}", orderId);
            throw;
        }
    }
}

Log Levels

Choose the right level for each message.

_logger.LogTrace("Fine-grained diagnostic information");
_logger.LogDebug("Debugging information for developers");
_logger.LogInformation("General application flow information");
_logger.LogWarning("Unexpected but recoverable situations");
_logger.LogError("Errors that prevent an operation from completing");
_logger.LogCritical("System failures requiring immediate attention");

Use LogLevel enum to configure minimum logging level in configuration.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "MyApp.OrderProcessor": "Debug"
    }
  }
}

Structured Logging

Always use structured logging with placeholders instead of string concatenation.

// Bad - string interpolation loses structure
_logger.LogInformation($"User {userId} logged in at {DateTime.UtcNow}");

// Good - structured logging preserves fields
_logger.LogInformation("User {UserId} logged in at {LoginTime}", userId, DateTime.UtcNow);

Structured logging allows log aggregation tools (Elasticsearch, Datadog, Seq) to index and search individual fields.

Setting Up Logging

Configure logging in a console application.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

var services = new ServiceCollection();
services.AddLogging(builder =>
{
    builder.ClearProviders();
    builder.AddConsole();
    builder.AddDebug();
    builder.SetMinimumLevel(LogLevel.Information);
});

services.AddTransient<OrderProcessor>();

var provider = services.BuildServiceProvider();
var processor = provider.GetRequiredService<OrderProcessor>();
processor.ProcessOrder(42);

Serilog

Serilog is the most popular structured logging library for C#.

using Serilog;
using Serilog.Formatting.Json;

// Configure Serilog
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Console()
    .WriteTo.File("logs/app-.log",
        rollingInterval: RollingInterval.Day,
        formatProvider: new JsonFormatter())
    .WriteTo.Seq("http://localhost:5341")
    .Enrich.WithProperty("Application", "MyApp")
    .Enrich.WithMachineName()
    .CreateLogger();

try
{
    Log.Information("Application starting up");

    var processor = new OrderProcessor();
    processor.ProcessOrder(100);
}
catch (Exception ex)
{
    Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
    Log.CloseAndFlush();
}

NLog

NLog is another powerful logging framework.

using NLog;

// NLog requires a NLog.config or programmatic configuration
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

public void DoWork()
{
    Logger.Info("Starting work with {Parameter}", "value");
    Logger.Error(new Exception("Something broke"), "Error details");
}

Log Enrichment

Add context to every log message automatically.

using var scope = _logger.BeginScope(new Dictionary<string, object>
{
    ["CorrelationId"] = Guid.NewGuid(),
    ["UserId"] = currentUser.Id
});

// All logs within this scope include CorrelationId and UserId
_logger.LogInformation("Processing payment");
_logger.LogWarning("Payment amount exceeds threshold");

Common Mistakes

  1. String interpolation in log messages: Always use structured placeholders ({Field}) instead of $"...". Structured logging preserves field names for searching.

  2. Logging sensitive data: Never log passwords, credit card numbers, or personal information. Use data masking or omit sensitive fields.

  3. Not using async logging: Synchronous logging can block your application. Most frameworks support async logging by default.

  4. Over-logging at Information level: Use Debug/Trace for verbose diagnostics and Information for meaningful business events.

  5. Ignoring log levels in production: Configure appropriate minimum log levels per namespace to avoid performance impact from excessive logging.

Practice Questions

  1. Set up a console application with console logging and file logging using Serilog.

  2. Create a custom ILoggerProvider that writes logs to a database table.

  3. Implement a logging middleware for ASP.NET Core that logs request duration and status code.

  4. Challenge: Build a log aggregation dashboard using SignalR that streams logs to a web client in real time.

FAQ

What is the difference between ILogger and ILogger?

ILogger is a generic interface where T is the owning class. The category name is automatically set to the full type name, making it easy to configure per-class log levels.

Should I use LogInformation or LogDebug for business events?

Use LogInformation for important business events (order placed, user registered). Use LogDebug for detailed internal flow that developers need during debugging.

How do I avoid logging performance overhead?

Use the IsEnabled pattern: if (_logger.IsEnabled(LogLevel.Debug)) before expensive log message preparation. Also configure appropriate minimum log levels.

What is structured logging?

Structured logging stores log data as structured fields (JSON) instead of plain text. This enables searching, filtering, and aggregating logs by field values.

Can I use multiple logging frameworks together?

Yes. ILogger is an abstraction that can have multiple providers (console, file, Seq) registered simultaneously.

Mini Project: Request Logging Middleware

Create an ASP.NET Core middleware that logs request information with timing.

using System.Diagnostics;
using Microsoft.Extensions.Logging;

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestLoggingMiddleware> _logger;

    public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var sw = Stopwatch.StartNew();

        _logger.LogInformation("HTTP {Method} {Path} started",
            context.Request.Method, context.Request.Path);

        await _next(context);

        sw.Stop();
        _logger.LogInformation("HTTP {Method} {Path} completed with {StatusCode} in {Duration}ms",
            context.Request.Method, context.Request.Path,
            context.Response.StatusCode, sw.ElapsedMilliseconds);
    }
}

// In Program.cs
// app.UseMiddleware<RequestLoggingMiddleware>();

Output (sample):

info: RequestLoggingMiddleware[0]
      HTTP GET /api/products started
info: RequestLoggingMiddleware[0]
      HTTP GET /api/products completed with 200 in 45ms

Effective logging is essential for production C# applications. By using structured logging with .NET's ILogger abstraction and tools like Serilog, you gain deep visibility into your application's behavior at runtime.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro