Md Mominul Islam | Software and Data Enginnering | SQL Server, .NET, Power BI, Azure Blog

while(!(succeed=try()));

LinkedIn Portfolio Banner

Latest

Home Top Ad

Responsive Ads Here

Post Top Ad

Responsive Ads Here

Tuesday, September 2, 2025

How to Implement Logging in ASP.NET Core using ILogger and Serilog

 

Introduction to Logging in ASP.NET Core

Logging is the backbone of application diagnostics, enabling developers to monitor, debug, and analyze system behavior. In ASP.NET Core, the built-in ILogger interface provides a flexible logging framework, while Serilog enhances it with structured logging and powerful sinks. This tutorial guides you from basic logging with ILogger to advanced setups with Serilog, covering real-world scenarios, best practices, pros and cons, and alternatives. Whether you’re building a small API or a large-scale enterprise application, this guide ensures your logging strategy is robust, scalable, and SEO-optimized for developers searching for practical solutions.

Why Logging Matters

  • Debugging: Identify and fix issues in development or production.
  • Monitoring: Track application performance and health.
  • Auditing: Log user actions for compliance or security.
  • Analytics: Analyze usage patterns or errors for improvements.

In real-world applications, logging helps troubleshoot errors (e.g., a failed payment transaction), monitor API performance, or track suspicious activities for security audits. This guide uses practical examples to make logging engaging and accessible.


Module 1: Getting Started with ILogger in ASP.NET Core

ASP.NET Core’s logging framework, built around the ILogger interface, is lightweight, extensible, and integrates with dependency injection (DI). It supports multiple providers like Console, Debug, and EventLog, making it a great starting point.

Understanding ILogger

The ILogger interface, part of Microsoft.Extensions.Logging, defines methods for logging at various levels:

  • Trace: Detailed diagnostics for developers.
  • Debug: Information for debugging during development.
  • Information: General application flow.
  • Warning: Unexpected but non-critical issues.
  • Error: Failures impacting functionality.
  • Critical: Severe errors requiring immediate attention.

Basic Setup

ASP.NET Core projects include logging by default. Let’s create a simple Web API to demonstrate.

Example 1: Basic Logging with ILogger

  1. Create a New ASP.NET Core Web API:

    bash
    dotnet new webapi -n LoggingDemo
    cd LoggingDemo
  2. Inject ILogger into a Controller: Modify Controllers/WeatherForecastController.cs:

    csharp
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    namespace LoggingDemo.Controllers
    {
    [ApiController]
    [Route("api/[controller]")]
    public class WeatherForecastController : ControllerBase
    {
    private readonly ILogger<WeatherForecastController> _logger;
    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
    _logger = logger;
    }
    [HttpGet]
    public IActionResult Get()
    {
    _logger.LogInformation("Fetching weather forecast at {Time}", DateTime.Now);
    try
    {
    var forecasts = new[] { "Sunny", "Cloudy", "Rainy" };
    _logger.LogDebug("Retrieved {Count} weather forecasts", forecasts.Length);
    return Ok(forecasts);
    }
    catch (Exception ex)
    {
    _logger.LogError(ex, "Failed to fetch weather forecasts");
    return StatusCode(500, "Internal server error");
    }
    }
    }
    }
  3. Configure Logging in appsettings.json:

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

Explanation:

  • ILogger<T> is injected via constructor, where T is the class type.
  • LogInformation and LogDebug log messages at different levels.
  • LogError includes the exception for detailed error tracking.
  • appsettings.json sets the minimum log level and filters Microsoft logs to reduce noise.

Sample Output (Console):

text
info: LoggingDemo.Controllers.WeatherForecastController[0]
Fetching weather forecast at 2025-09-02 17:45:23
dbg: LoggingDemo.Controllers.WeatherForecastController[0]
Retrieved 3 weather forecasts

Pros and Cons of ILogger

Pros:

  • Built-in, no external dependencies.
  • Seamless DI integration.
  • Supports multiple providers (Console, Debug, EventLog).

Cons:

  • Lacks structured logging for advanced querying.
  • Limited sink options for production-grade logging.
  • Basic formatting may not suffice for complex analytics.

Module 2: Powering Up with Serilog

Serilog is a third-party logging library that adds structured logging, rich formatting, and support for numerous sinks (e.g., files, databases, cloud services). It’s ideal for real-world applications needing advanced logging capabilities.

Why Serilog?

  • Structured Logging: Logs data as JSON for querying and analytics.
  • Rich Sinks: Supports file, database, Seq, Elasticsearch, and more.
  • Extensibility: Customizable for specific needs.

Setting Up Serilog

  1. Install NuGet Packages:

    bash
    dotnet add package Serilog.AspNetCore
    dotnet add package Serilog.Sinks.Console
    dotnet add package Serilog.Sinks.File
  2. Configure Serilog in Program.cs: Replace the default Program.cs:

    csharp
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    using Serilog;
    namespace LoggingDemo
    {
    public class Program
    {
    public static void Main(string[] args)
    {
    Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Console()
    .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day)
    .CreateLogger();
    try
    {
    Log.Information("Application starting...");
    CreateHostBuilder(args).Build().Run();
    }
    catch (Exception ex)
    {
    Log.Fatal(ex, "Application failed to start");
    }
    finally
    {
    Log.CloseAndFlush();
    }
    }
    public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .UseSerilog()
    .ConfigureWebHostDefaults(webBuilder =>
    {
    webBuilder.UseStartup<Startup>();
    });
    }
    }
  3. Configure via appsettings.json:

    json
    {
    "Serilog": {
    "MinimumLevel": {
    "Default": "Information",
    "Override": {
    "Microsoft": "Warning",
    "System": "Warning"
    }
    },
    "WriteTo": [
    { "Name": "Console" },
    {
    "Name": "File",
    "Args": {
    "path": "logs/app-.log",
    "rollingInterval": "Day"
    }
    }
    ]
    }
    }
  4. Load Configuration: Update Program.cs to read from appsettings.json:

    csharp
    Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(builder.Configuration)
    .CreateLogger();

Explanation:

  • Serilog.AspNetCore integrates with ASP.NET Core’s logging.
  • WriteTo.Console outputs to the console.
  • WriteTo.File creates daily log files (e.g., app-20250902.log).
  • ReadFrom.Configuration loads settings from appsettings.json.

Example 2: Structured Logging with Serilog

Update the WeatherForecastController for structured logging:

csharp
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace LoggingDemo.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet("{city}")]
public IActionResult Get(string city)
{
_logger.LogInformation("Fetching weather for {City} at {Time}", city, DateTime.Now);
try
{
var forecast = new { City = city, Condition = "Sunny", Temperature = 25 };
_logger.LogInformation("Retrieved forecast for {City}: {Condition}, {Temperature}°C", city, forecast.Condition, forecast.Temperature);
return Ok(forecast);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to fetch weather for {City}", city);
return StatusCode(500, "Internal server error");
}
}
}
}

Sample Log Output (Console):

text
[2025-09-02T17:45:23.123 INF] Fetching weather for NewYork at 2025-09-02 17:45:23
[2025-09-02T17:45:23.456 INF] Retrieved forecast for NewYork: Sunny, 25°C

Sample Log Output (File: logs/app-20250902.log):

json
{"Timestamp":"2025-09-02T17:45:23.1234567+06:00","Level":"Information","MessageTemplate":"Fetching weather for {City} at {Time}","Properties":{"City":"NewYork","Time":"2025-09-02T17:45:23.1234567+06:00"}}

Explanation:

  • Structured logging captures properties (e.g., {City}, {Time}) as key-value pairs.
  • Logs are written to console and file sinks.
  • JSON format enables querying in tools like Seq or Elasticsearch.

Pros and Cons of Serilog

Pros:

  • Structured logging for advanced analytics.
  • Supports numerous sinks (file, database, Seq, etc.).
  • Highly customizable.

Cons:

  • External dependency adds complexity.
  • Configuration can be overwhelming for beginners.
  • Slight performance overhead for heavy logging.

Module 3: Advanced Logging Scenarios

Scenario 1: Logging to a Database

For centralized logging, store logs in a database like SQL Server.

  1. Install NuGet Package:
    bash
    dotnet add package Serilog.Sinks.MSSqlServer
  2. Configure SQL Server Sink: Update appsettings.json:
    json
    {
    "Serilog": {
    "WriteTo": [
    {
    "Name": "MSSqlServer",
    "Args": {
    "connectionString": "Server=localhost;Database=Logs;Trusted_Connection=True;",
    "tableName": "Logs",
    "autoCreateSqlTable": true
    }
    }
    ]
    }
    }
  3. Database Schema (Auto-created):
    sql
    CREATE TABLE Logs (
    Id bigint IDENTITY(1,1) PRIMARY KEY,
    Message nvarchar(max),
    MessageTemplate nvarchar(max),
    Level varchar(128),
    TimeStamp datetimeoffset,
    Exception nvarchar(max),
    Properties xml
    )

Explanation:

  • Logs are stored in a SQL Server table.
  • Properties column stores structured data as XML.
  • autoCreateSqlTable creates the table automatically.

Scenario 2: Enriching Logs

Add contextual information like user ID or environment details.

  1. Install Enrichers:
    bash
    dotnet add package Serilog.Enrichers.Thread
    dotnet add package Serilog.Enrichers.Environment
  2. Update Configuration:
    csharp
    Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(builder.Configuration)
    .Enrich.WithThreadId()
    .Enrich.WithEnvironmentName()
    .CreateLogger();

Sample Log Output:

json
{
"Timestamp": "2025-09-02T17:45:23.1234567+06:00",
"Level": "Information",
"MessageTemplate": "Fetching weather for {City}",
"Properties": {
"City": "NewYork",
"ThreadId": 1,
"EnvironmentName": "Development"
}
}

Scenario 3: Centralized Logging with Seq

Seq is a powerful tool for visualizing and querying structured logs.

  1. Install Seq Sink:
    bash
    dotnet add package Serilog.Sinks.Seq
  2. Configure Seq:
    json
    {
    "Serilog": {
    "WriteTo": [
    {
    "Name": "Seq",
    "Args": {
    "serverUrl": "http://localhost:5341"
    }
    }
    ]
    }
    }
  3. Run Seq:
    • Download Seq and run locally or use a hosted instance.
    • Access logs via Seq’s web interface for querying and visualization.

Example Seq Query:

sql
SELECT City, COUNT(*)
FROM Logs
WHERE Level = 'Information'
GROUP BY City

Scenario 4: Request Logging Middleware

Log HTTP requests for monitoring API usage.

csharp
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace LoggingDemo.Middleware
{
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)
{
_logger.LogInformation("Handling request: {Method} {Path}", context.Request.Method, context.Request.Path);
await _next(context);
_logger.LogInformation("Response: {StatusCode}", context.Response.StatusCode);
}
}
}

Register Middleware in Startup.cs:

csharp
app.UseMiddleware<RequestLoggingMiddleware>();

Sample Log Output:

text
[2025-09-02T17:45:23.123 INF] Handling request: GET /api/weatherforecast/NewYork
[2025-09-02T17:45:23.456 INF] Response: 200

Module 4: Best Practices and Standards

Best Practices

  1. Use Structured Logging: Prefer Serilog for structured data to enable querying.
  2. Log Meaningful Data: Include context (e.g., user ID, request ID) but avoid sensitive information (e.g., passwords).
  3. Set Appropriate Log Levels:
    • Development: Use Debug or Trace.
    • Production: Use Information or higher to reduce noise.
  4. Centralize Logs: Use tools like Seq, Elasticsearch, or cloud services for centralized logging.
  5. Handle Exceptions Properly: Always include exceptions in LogError or LogCritical.
  6. Optimize Performance:
    • Use asynchronous sinks (e.g., Serilog.Sinks.Async).
    • Filter logs to avoid excessive writes.

Standards

  • Follow Semantic Logging: Use consistent message templates (e.g., Fetching {Resource} for {UserId}).
  • Adhere to Compliance: Ensure logs meet GDPR, HIPAA, or other regulations by anonymizing sensitive data.
  • Use Correlation IDs: Track requests across services with unique IDs.

Module 5: Alternatives to Serilog

  1. NLog:
    • Pros: Flexible, supports many targets, easy configuration.
    • Cons: Less focus on structured logging compared to Serilog.
    • Use Case: Suitable for legacy applications or simpler logging needs.
  2. log4net:
    • Pros: Mature, widely used, configurable.
    • Cons: Older API, less modern than Serilog.
    • Use Case: Good for existing .NET Framework projects.
  3. Microsoft.Extensions.Logging Providers:
    • Pros: Built-in, no dependencies (e.g., Console, EventLog).
    • Cons: Limited features for advanced scenarios.
    • Use Case: Quick setups or minimal logging needs.

Module 6: Real-World Example – E-Commerce Application

Let’s apply logging to an e-commerce API handling product orders.

Example 3: Logging in an E-Commerce API

csharp
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
namespace ECommerceApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class OrderController : ControllerBase
{
private readonly ILogger<OrderController> _logger;
public OrderController(ILogger<OrderController> logger)
{
_logger = logger;
}
[HttpPost]
public IActionResult PlaceOrder([FromBody] Order order)
{
var correlationId = Guid.NewGuid().ToString();
_logger.LogInformation("Processing order {OrderId} for {CustomerId}. CorrelationId: {CorrelationId}", order.OrderId, order.CustomerId, correlationId);
try
{
// Simulate order processing
if (order.Quantity <= 0)
throw new ArgumentException("Invalid quantity");
_logger.LogInformation("Order {OrderId} placed successfully. Total: {Total}", order.OrderId, order.Total);
return Ok(new { OrderId = order.OrderId, Status = "Placed" });
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to process order {OrderId}. CorrelationId: {CorrelationId}", order.OrderId, correlationId);
return StatusCode(500, "Order processing failed");
}
}
}
public class Order
{
public string OrderId { get; set; }
public string CustomerId { get; set; }
public int Quantity { get; set; }
public decimal Total { get; set; }
}
}

Sample Log Output:

json
{
"Timestamp": "2025-09-02T17:45:23.1234567+06:00",
"Level": "Information",
"MessageTemplate": "Processing order {OrderId} for {CustomerId}. CorrelationId: {CorrelationId}",
"Properties": {
"OrderId": "ORD123",
"CustomerId": "CUST456",
"CorrelationId": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
}
}

Explanation:

  • Logs include a CorrelationId for tracking requests across services.
  • Structured properties (OrderId, CustomerId) enable querying.
  • Errors are logged with exceptions for detailed diagnostics.

Conclusion

Logging in ASP.NET Core with ILogger and Serilog empowers developers to build robust, monitorable applications. From basic console logging to advanced setups with Seq or databases, this guide covers practical scenarios with real-world examples. By following best practices and leveraging structured logging, you can ensure your application is debuggable, scalable, and compliant. Explore alternatives like NLog or built-in providers based on your project’s needs, and use centralized logging for production-grade monitoring.

No comments:

Post a Comment

Thanks for your valuable comment...........
Md. Mominul Islam

Post Bottom Ad

Responsive Ads Here