Skip to main content

Command Palette

Search for a command to run...

Understanding ILogger in .NET Core

A Complete Guide for Developers

Published
4 min read
Understanding ILogger in .NET Core
M

Morteza Jangjoo, Senior .NET Backend Developer with 15+ years of experience in C#, ASP.NET Core, SQL Server, and Microservices. Skilled in building scalable, high-performance systems.

Logging is one of the most essential parts of any application — it helps developers track what’s happening inside their system, debug issues, and monitor production environments.

In .NET Core, logging is built-in through the ILogger interface, which is part of the Microsoft.Extensions.Logging namespace.
This powerful and flexible abstraction allows you to log messages to multiple providers like Console, File, Debug, Seq, Elasticsearch, and more — all through a unified API.


What is ILogger?

ILogger is a generic logging interface provided by .NET Core for writing log messages.
It abstracts the actual logging implementation, so you can easily switch between different log providers without changing your application code.

The interface is defined as:

public interface ILogger
{
    IDisposable BeginScope<TState>(TState state);
    bool IsEnabled(LogLevel logLevel);
    void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter);
}

However, in practice, we rarely call these methods directly.
Instead, we use the extension methods like LogInformation(), LogWarning(), and LogError().


Adding Logging to a .NET Core Application

Logging in .NET Core is configured through Dependency Injection (DI).
When you create a new project (like using dotnet new webapi), the logging infrastructure is already available.

Let’s see it in action.

Example: Logging in a Controller

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace LoggingDemo.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherController : ControllerBase
    {
        private readonly ILogger<WeatherController> _logger;

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

        [HttpGet]
        public IActionResult Get()
        {
            _logger.LogInformation("Weather forecast requested at {Time}", DateTime.UtcNow);

            try
            {
                // Simulate some logic
                var data = new[] { "Sunny", "Cloudy", "Rainy" };
                return Ok(data);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error while fetching weather data");
                return StatusCode(500, "Internal Server Error");
            }
        }
    }
}

In this example:

  • ILogger<T> automatically injects a logger for the WeatherController.

  • We log an information message before processing and an error message if something goes wrong.


Log Levels

.NET Core supports the following log levels (from most to least severe):

Log LevelDescription
CriticalFor critical errors that cause complete failure
ErrorFor runtime errors that require attention
WarningFor abnormal or unexpected events
InformationFor general app flow messages
DebugFor debugging information, often used during development
TraceFor detailed, low-level debugging information

You can filter logs based on these levels in appsettings.json.


Configuring Logging in appsettings.json

You can control what gets logged by editing the Logging section in your configuration file:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

This configuration means:

  • Your app logs everything from Information and above.

  • Microsoft system logs (framework logs) are limited to Warning or higher.


Adding Custom Logging Providers

Out of the box, .NET Core supports several logging providers like:

  • Console

  • Debug

  • EventSource

  • EventLog

You can also integrate third-party providers like:

  • Serilog

  • NLog

  • Seq

  • Elasticsearch

Example with Serilog:

public static class Program
{
    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day)
            .CreateLogger();

        try
        {
            Log.Information("Starting web host");
            CreateHostBuilder(args).Build().Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly");
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseSerilog() // Add Serilog here
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Structured Logging with Message Templates

Instead of concatenating strings, ILogger uses structured logging, which is both cleaner and more efficient.

Example:

_logger.LogInformation("User {UserId} logged in at {LoginTime}", userId, DateTime.UtcNow);

This logs data in a structured format like JSON (depending on the provider), making it easier to query and analyze logs in tools like Seq or Elastic Stack.


Using Scopes for Contextual Logging

Scopes allow you to group log messages that share a common context (for example, a request ID or user ID).

using (_logger.BeginScope("TransactionId: {TransactionId}", Guid.NewGuid()))
{
    _logger.LogInformation("Processing started");
    _logger.LogInformation("Processing completed");
}

All logs inside the scope will include the TransactionId automatically — very useful for debugging distributed or concurrent operations.


Summary

ILogger is the heart of .NET Core’s logging system.
It’s provider-independent and works seamlessly with dependency injection.
Supports structured logging, log levels, and scopes for context.
Easily extensible with providers like Serilog, NLog, or Seq.

Using ILogger effectively means you can keep your logs clean, consistent, and ready for deep analysis — essential for production-grade applications.


Example GitHub Repository

You can find a working example here:
👉 https://github.com/Morteza-Jangjoo/ILogging


I’m Morteza Jangjoo and “Explaining things I wish someone had explained to me”