DEV Community

Cover image for Proper Logging in ASP.NET Core
Mo
Mo

Posted on

2 1 1

Proper Logging in ASP.NET Core

Hey there, fellow code warriors! ๐Ÿ‘‹ Today, we're diving deep into proper logging in ASP.NET Core. If you've ever found yourself lost in a sea of mysterious bugs or scratching your head over your application's behaviour, this guide is your lighthouse! ๐Ÿ๏ธ

Logging details

Why Logging Matters ๐Ÿค”

Before we jump into the code, let's talk about why logging is the unsung hero of software development. Proper logging is like giving your future self (and your team) a roadmap to understand what's happening in your application. It's not just about catching errors; it's about gaining insights, improving performance, and making your development life easier.

Here's why logging is crucial for your projects:

  1. Application Behavior Monitoring: It's like having a 24/7 surveillance camera on your code.
  2. Event Capturing: Every important moment in your app's life, documented.
  3. Performance Insights: Because sometimes, your app needs a health check.

But logging isn't just about writing stuff down. It's part of a trio of concepts that make your applications robust, maintainable, and scalable:

The Holy Trinity of Application Observability ๐Ÿ› ๏ธ

  1. Logging: Your app's diary ๐Ÿ“”

    • Records events, errors, and important information
    • Helps debug issues quickly
    • Provides insights into application behaviour
  2. Traceability: Following the breadcrumbs of your code ๐Ÿž

    • Tracks the flow of application processes
    • Follows the lifecycle of requests or commands
    • Especially helpful for distributed systems or microservices
    • Facilitates debugging and enhances reliability
  3. Metrics: Measuring what matters ๐Ÿ“Š

    • Provides measurable data about application performance
    • Helps make data-driven decisions
    • Enhances user experiences through targeted optimizations

logging is a hero

Implementing Logging with Serilog in ASP.NET Core ๐Ÿ› ๏ธ

Let's roll up our sleeves and get our hands dirty with some code! We'll be using Serilog, a powerful logging library for .NET.

Setting Up Serilog

First, add the Serilog.AspNetCore NuGet package to your project. If you're planning to use Azure Application Insights, grab Serilog.Sinks.AzureApp too.

In your Program.cs, set up Serilog like this:

builder.Logging.ClearProviders();
builder.Host.UseSerilog(((context, configuration) => 
    configuration.ReadFrom.Configuration(context.Configuration)));
Enter fullscreen mode Exit fullscreen mode

This code clears any existing logging providers and tells Serilog to read its configuration from the appsettings.json file.

Configuring Serilog

In your appsettings.json, you can configure Serilog like a boss:

{
    "Serilog": {
    "Using": [
      "Serilog.Sinks.Console",
      "Serilog.Sinks.File"
    ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
        }
      },
      {
        "Name": "File",
        "Args": {
          "path": "Logs/log-.txt",
          "rollingInterval": "Day",
          "rollOnFileSizeLimit": true,
          "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}",
          "fileSizeLimitBytes": 1073741824
        }
      },
      {
        "Name": "AzureApp",
        "Args": {
          "instrumentationKey": "your_instrumentation_key"
        }
      }
    ],
    "Enrich": [
      "FromLogContext",
      "WithMachineName",
      "WithThreadId"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

This configuration sets up Serilog to:

  • Use both console and file sinks
  • Set default log levels (Information for production, Debug for development)
  • Write logs to the console and a file
  • Send logs to Azure Application Insights

Logging in Action: GlobalExceptionHandler ๐ŸŽญ

Our GlobalExceptionHandler class is like a superhero for exceptions. It catches them, logs them, and sends back a nicely formatted response to the user.

public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
    // ... (exception handling logic)

    _logger.LogError(exception, "An error occurred while processing the request {DateTime} {Path}", 
        DateTime.UtcNow, httpContext.Request.Path);

    // ... (return problem details)
}
Enter fullscreen mode Exit fullscreen mode

This class inherits from IExceptionHandler and is registered in our dependency injection setup. It formats errors based on their type and logs them in a structured way before returning a user-friendly response.

Request Logging with LoggingBehaviour ๐Ÿ•ต๏ธ

The LoggingBehaviour class is our secret agent, tracking every request that passes through our application.

public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken)
{
    Stopwatch stopWatch = Stopwatch.StartNew();
    logger.LogInformation("Handling request {Name}, {DateTime} ", request.GetType().Name, DateTime.UtcNow);

    // ... (request handling)

    if (stopWatch.ElapsedMilliseconds > SlowRequestThresholdMilliseconds)
    {
        logger.LogWarning("Request took too long to handle {Name}, {DateTime}, {ElapsedMilliseconds}ms", 
            request.GetType().Name, DateTime.UtcNow, stopWatch.ElapsedMilliseconds);
    }

    if (result.IsSuccess)
    {
        logger.LogInformation("Request handled successfully {Name}, {DateTime}", request.GetType().Name, DateTime.UtcNow);
    }
    else
    {
        logger.LogError("Request failed to handle {Name}, {DateTime}, {@Error}", request.GetType().Name, DateTime.UtcNow, result.Errors);
    }

    // ... (log success or failure)
}
Enter fullscreen mode Exit fullscreen mode

This class implements IPipelineBehavior from the MediatR library, acting as a pipeline for each request. It measures request duration, logs warnings for slow requests, and records the outcome of each request.

Pro Tips for Logging Like a Boss ๐Ÿ˜Ž

  1. Use Structured Logging: Always include relevant context in your logs. Serilog makes this easy with templates.
  2. Log Levels Matter: Use the right log level for the right situation. Not everything is an error!
  3. Performance Matters: Logging can impact performance, so use it wisely.
  4. Sensitive Data Alert: Be careful not to log sensitive information. Your logs shouldn't be a security risk!
  5. Use the "@" Symbol: When logging objects with Serilog, use the "@" symbol (e.g., {@Error}) to serialize the entire object. This makes querying logs easier, especially with tools like Seq.

Wrapping Up ๐ŸŽ

Proper logging is an essential skill for any developer working with ASP.NET Core. It's not just about catching errors; it's about gaining insights, improving performance, and making your development life easier.

Remember, your logs are your best friend when things go wrong (and even when they don't). They're your application's black box, recording every important event and helping you understand what's happening under the hood.

So, the next time you're debugging a tricky issue or trying to understand why your app is behaving weirdly, remember: that your logs are there to help. Happy logging, developers! ๐Ÿš€

The source code is available in my Github repo.

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

๐Ÿ‘ฅ Ideal for solo developers, teams, and cross-company projects

Learn more

๐Ÿ‘‹ Kindness is contagious

If you found this article helpful, a little โค๏ธ or a friendly comment would be much appreciated!

Got it