Understanding ILogger in .NET Core — A Complete Guide
Logging is an essential part of every modern application. It helps you understand what’s happening inside your system, debug problems faster, and monitor production environments effectively.
In .NET Core, logging is built-in through the ILogger interface, part of the Microsoft.Extensions.Logging namespace.
This powerful abstraction allows developers to log messages to multiple providers like Console, File, Seq, Elasticsearch, and more — all using a consistent API.
What is ILogger?
ILogger is the core logging interface in .NET Core that provides a unified way to write log messages.
It abstracts away the underlying implementation, so you can change the logging provider without touching your application logic.
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, developers typically use extension methods like LogInformation(), LogWarning(), and LogError() instead of calling these methods directly.
🔹 Basic Usage in .NET Core
Logging in .NET Core is automatically registered in the Dependency Injection (DI) container.
When you create a new Web API project, it’s already wired up.
Here’s how to use it inside 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
{
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");
}
}
}
}
✅ Here we:
- Inject
ILogger<WeatherController>using DI. - Log an information message and an error message.
- Use structured logging (with placeholders like
{Time}).
Log Levels in .NET Core
| Log Level | Description |
|---|---|
Critical |
Application crash or serious failure |
Error |
Recoverable runtime error |
Warning |
Unexpected or abnormal events |
Information |
General application flow messages |
Debug |
Detailed debug info (used during development) |
Trace |
Very detailed, low-level diagnostic info |
You can control what gets logged using appsettings.json.
Configure Logging in appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
This configuration:
- Logs all messages from
Informationlevel and higher for your app. - Limits Microsoft framework logs to
Warningand higher.
Setting up Logging in Program.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
var builder = WebApplication.CreateBuilder(args);
// Configure logging
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddDebug();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Structured Logging
Structured logging helps you avoid messy string concatenation.
Instead of writing:
_logger.LogInformation("User " + userId + " logged in at " + DateTime.UtcNow);
Write this instead:
_logger.LogInformation("User {UserId} logged in at {LoginTime}", userId, DateTime.UtcNow);
This logs data in a structured, queryable format (like JSON) — great for tools like Seq, Serilog, or Elastic Stack.
Using Scopes for Contextual Logs
Scopes allow you to associate related log entries with shared context (e.g., request ID, transaction ID).
using (_logger.BeginScope("TransactionId: {TransactionId}", Guid.NewGuid()))
{
_logger.LogInformation("Transaction started");
_logger.LogInformation("Transaction completed");
}
All log entries inside the scope will include the same TransactionId, which helps with tracing.
Adding Third-Party Providers (Serilog Example)
Want to store logs in files or send them to a log server?
Integrate Serilog with just a few lines.
Install packages:
dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.File
Then update your Program.cs:
using Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Example Project
You can download a full working example here:
👉 Github
This includes:
Program.csWeatherController.csappsettings.json-
.csprojfile
Summary
ILogger is the foundation of logging in .NET Core.
It’s framework-independent, provider-based, and fully configurable.
Supports structured logging, log levels, and scopes.
Easily integrates with Serilog, NLog, Seq, or Elastic Stack.
With a good logging strategy, you can understand user behavior, detect issues early, and monitor your application health in production.
I’m Morteza Jangjoo and “Explaining things I wish someone had explained to me”
Top comments (0)