In today's modern applications, logging and monitoring play a crucial role in ensuring the health, reliability, and performance of software. These two practices allow developers and DevOps teams to diagnose issues quickly, track performance bottlenecks, and stay ahead of potential failures. ASP.NET Core provides a built-in logging framework, along with flexibility to integrate powerful monitoring tools to track application health in real time.

In this article, we’ll explore how to implement logging and monitoring in .NET Core applications using built-in tools like ILogger<T>, as well as third-party tools like Serilog for persistent logging and custom middleware for performance tracking.

Why Logging and Monitoring Matter

Both logging and monitoring serve distinct but equally important purposes in application development and production environments:

Logging in ASP.NET Core

ASP.NET Core uses a powerful built-in logging system that helps you log messages across different components of the application. The ILogger<T> interface is central to this logging system, allowing developers to log messages at various levels such as Information, Warning, and Error.

Step 1: Implementing Basic Logging in Controllers

Here’s how you can use the built-in logging functionality in an ASP.NET Core controller:

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly ILogger<ProductsController> _logger;

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

    [HttpGet]
    public IActionResult GetProducts()
    {
        _logger.LogInformation("Fetching all products at {time}", DateTime.UtcNow);
        return Ok(new[] { "Laptop", "Smartphone" });
    }
}

In this example:

Step 2: Configuring Logging Levels in appsettings.json

To control the verbosity of logs, ASP.NET Core allows you to define log levels in appsettings.json. The configuration specifies what types of logs (Information, Warning, Error) should be captured for different categories, including the default logger and Microsoft-specific categories.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "System": "Error"
    }
  }
}

Connecting Logs to a Database with Serilog

Sometimes, you need persistent logging stored in a database for later analysis, auditing, or troubleshooting. Serilog is a popular logging library that supports different sinks, including database sinks such as SQL Server. Here's how to configure and use Serilog in an ASP.NET Core application:

Step 1: Install Serilog Packages

First, you need to install the Serilog packages. You can do this using the following command:

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.MSSqlServer

Step 2: Configure Serilog in Program.cs

Next, configure Serilog in the Program.cs file to write logs to a SQL Server database:

using Serilog;

var builder = WebApplication.CreateBuilder(args);

// Configure Serilog with SQL Server sink
Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .WriteTo.MSSqlServer(
        connectionString: builder.Configuration.GetConnectionString("DefaultConnection"),
        sinkOptions: new Serilog.Sinks.MSSqlServer.MSSqlServerSinkOptions
        {
            TableName = "Logs",
            AutoCreateSqlTable = true
        })
    .CreateLogger();

builder.Host.UseSerilog();

builder.Services.AddControllers();

var app = builder.Build();
app.MapControllers();
app.Run();

In this example:

Step 3: Database Table

Serilog will automatically create a table in your SQL Server database with the following columns:

Monitoring with Metrics

While logging is essential for diagnosing issues, monitoring provides insights into the application's performance and health in real time. Metrics such as request duration, error rates, and resource usage can be tracked and visualized using monitoring tools.

One common practice in monitoring is adding custom middleware to measure the duration of HTTP requests.

Example: Middleware for Request Timing

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

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

    public async Task InvokeAsync(HttpContext context)
    {
        var start = DateTime.UtcNow;
        await _next(context);
        var duration = DateTime.UtcNow - start;

        _logger.LogInformation("Request {path} took {duration} ms",
            context.Request.Path, duration.TotalMilliseconds);
    }
}

Register Middleware in Program.cs

app.UseMiddleware<RequestTimingMiddleware>();

Example in Action

Consider an E-Commerce API:

This setup provides you with a complete monitoring and logging solution, allowing developers to trace errors, measure performance, and monitor system health in real time.

Conclusion

Logging and monitoring are vital components of any modern .NET Core application. By utilizing the built-in logging framework and integrating with powerful third-party tools like Serilog for persistent logging and custom middleware for performance tracking, developers gain valuable insights into the behavior of their application.

By also incorporating monitoring tools such as Grafana or Azure Application Insights, you ensure proactive detection of issues before they become critical. This approach not only improves troubleshooting and performance optimization but also helps keep your application reliable in production.

With this guide, you now have a solid foundation for logging and monitoring in your .NET Core projects. By implementing the techniques discussed, your applications will be more robust and easier to maintain in production environments.