Structured logging – Logging patterns

As stated at the beginning, structured logging can become very important and open opportunities. Querying a data structure is always more versatile than querying a single line of text. That is even more true if there is no clear guideline around logging, whether a line of text or a JSON-formatted data structure.To keep it simple, we leverage a built-in formatter (highlighted line below) that serializes our log entries into JSON. Here is the Program.cs file:

var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddJsonConsole();
var app = builder.Build();
app.MapGet(“/”, (ILoggerFactory loggerFactory) =>
{
    const string category = “root”;
    var logger = loggerFactory.CreateLogger(category);
    logger.LogInformation(“You hit the {category} URL!”, category);
    return “Hello World!”;
});
app.Run();

That transforms the console to logging JSON. For example, every time we hit the / endpoint, the console displays the following JSON:

{
  “EventId”: 0,
  “LogLevel”: “Information”,
  “Category”: “root”,
  “Message”: “You hit the root URL!”,
  “State”: {
    “Message”: “You hit the root URL!”,
    “category”: “root”,
    “{OriginalFormat}”: “You hit the {category} URL!”
 
}
}

Without that formatter, the usual output would have been:

info: root[0]
      You hit the root URL!

Based on that comparison, it is more versatile to query the JSON logs programmatically than the stdout line.The biggest benefit of structured logging is improved searchability. You can run more precise queries at scale with a predefined data structure.Of course, if you are setting up a production system, you would probably want more information attached to such log items like the correlation ID of the request, optionally some information about the current user, the server’s name on which the code is running, and possibly more details depending on the application.You may need more than the out-of-the-box features to utilize structured logging fully. Some third-party libraries like Serilog offer those additional capabilities. However, defining the way to send plain text to the logger could be a start.Each project should dictate the needs and depth of each feature, including logging. Moreover, structured logging is a broader subject that merits studying independently. Nonetheless, I wanted to touch on this subject a bit, and hopefully, you learned enough about logging to get started.

Summary

In this chapter, we delved into the concept of logging. We learned that logging is the practice of recording messages into a log for later use, such as debugging errors, tracing operations, and analyzing usage. Logging is essential, and ASP.NET Core offers us various ways to log information independently of third-party libraries while allowing us to use our favorite logging framework. We can customize the way the logs are written and categorized. We can use zero or more logging providers. We can also create custom logging providers. Finally, we can use configurations or code to filter logs and much more.Here is the default logging pattern to remember:

  1. Inject an ILogger<T>, where T is the type of the class into which the logger is injected. T becomes the category.
  2. Save a reference of that logger into a private readonly ILogger field.
  3. Use that logger in your methods to log messages using the appropriate log level.

The logging system is a great addition to .NET Core compared to .NET Framework. It allows us to standardize the logging mechanism, making our systems easier to maintain in the long run. For example, suppose you want to use a new third-party library or even a custom-made one. In that case, you can load the provider into your Program, and the entire system will adapt and start using it without any further changes as long as you depend only on the logging abstractions. This is a good example of what well-designed abstractions can bring to a system.Here are a few key takeaways:

  • Logging is a cross-cutting concern, affecting all layers of an application.
  • A log comprises many log entries representing an event that occurred at runtime during the program’s execution.
  • The severity of a log entry is important for filtering and prioritization.
  • The severity levels are Trace, Debug, Information, Warning, Error, and Critical.
  • We can configure the logging system to log only certain messages based on the severity level of each entry.
  • Structured logging can help maintain consistency and ease of searching within logs.
  • The logging system in .NET is provider-based, allowing us to customize the default providers.
  • We can use interfaces like ILogger, ILogger<T>, or ILoggerFactory to create log entries.

This chapter closes the second section of this book with ASP.NET Core at its center. We explore design patterns to create flexible and robust components in the next few chapters.

Leave a Reply

Your email address will not be published. Required fields are marked *



          Copyright © 2015-2024 | About | Terms of Service | Privacy Policy