DEV Community

Fabrizio Bagalà
Fabrizio Bagalà

Posted on • Edited on

Logging in ASP.NET

ℹ️ Information
The code in the following article was tested with ASP.NET 6 and 7.

Logging is an essential component for software development and maintenance. It helps us understand what is happening inside our applications, identify errors and unexpected behaviors, troubleshoot problems, and is also useful for auditing operations.

Create logs

In ASP.NET, logging is typically performed by obtaining an ILogger or ILogger<T> instance through dependency injection, and then using that instance to log messages.

Here is a step-by-step guide on how to set up and use logging:

Step 1: Configure logging in appsettings.json

One of the first steps you often do is to set up the logging configuration in your application's appsettings.json file. This allows you to set the default logging level and define different logging levels for different categories.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Add logging services in Program.cs

In your Program.cs file, you can add and configure various logging providers, such as Console, Debug, or others.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddLogging(config =>
{
    config.AddConsole();
    config.AddDebug();
    // Other logging providers
});

// ...
Enter fullscreen mode Exit fullscreen mode

Step 3: Set up dependency injection for the logger in your class

Within the classes where you want to do the logging, such as a controller, you would set up dependency injection to get an instance of ILogger or ILogger<T>.

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Use the logger to log messages

Finally, you can use the _logger instance to log messages at various severity levels (from Trace to Critical).

public IActionResult Index()
{
    _logger.LogInformation("Calling the Index method");
    return View();
}
Enter fullscreen mode Exit fullscreen mode

Configure logging

Logging can be easily configured either in the code or through configuration files, such as appsettings.json. This configuration file can be used to enable or disable log providers, modify log levels, or even filter log messages. Typically, the Logging section of the appsettings.{ENVIRONMENT}.json files (where {ENVIRONMENT} is the environment placeholder) provides the logging configuration.

A standard example of what a logging configuration might look like in an appsettings.json file is as follows:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the default log level is set to Information, and the log level for all categories that begin with Microsoft.AspNetCore is set to Warning.

The LogLevel can be set for specific providers (like Logging:EventSource:LogLevel:Default:Information), specific categories (like Logging:LogLevel:Microsoft.AspNetCore:Critical), or all providers and all categories (like Logging:LogLevel:Default:Warning). Any logs below the set minimum level will not be logged or displayed.

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore": "Critical"
    },
    "EventSource": {
      "LogLevel": {
        "Default": "Information"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

To mute all logs, you can specify LogLevel.None.

{
  "Logging": {
    "LogLevel": {
      "Default": "None"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This logging configuration offers a high degree of flexibility, enabling you to customize logging behavior to suit your application's requirements.

Log category

When you make a new ILogger, you pick a category. Each log message from this ILogger will have this category attached. Typically, the category is the name of the class. For instance, you might use ILogger<T> to automatically set the category to be the same as the type name T.

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

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

    public IActionResult Index()
    {
        _logger.LogInformation("Calling the Index method");
        return View();
    }
}
Enter fullscreen mode Exit fullscreen mode

If you want to pick the category yourself, you can use CreateLogger from ILoggerFactory. This is handy if you want to group log messages from different places under the same category.

public class HomeController : Controller
{
    private readonly ILogger _logger;

    public HomeController(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger("MyCategory");
    }

    public IActionResult Index()
    {
        _logger.LogInformation("Calling the Index method");
        return View();
    }
}
Enter fullscreen mode Exit fullscreen mode

So, using ILogger<T> is like using CreateLogger, but with the category being automatically set to the type name of T.

Log level

A log level acts as a control mechanism to determine the depth of detail for your log messages. Each log level corresponds to a particular degree of seriousness and is often utilized to exclude logs of less critical nature.

The following table presents an overview of the different log levels:

LogLevel Value Method Description
Trace 0 LogTrace Contains the most detailed messages. These messages may contain sensitive application data and are typically used for debugging.
Debug 1 LogDebug Used for informational messages that might be useful during development and debugging.
Information 2 LogInformation Used to track the general flow of the application. These messages may have long-term value in understanding app behavior.
Warning 3 LogWarning Used for abnormal or unexpected events. Typically includes errors or conditions that don't cause the app to fail but might indicate potential issues.
Error 4 LogError Used for errors and exceptions that cannot be handled. These messages indicate a failure in the current operation or request, not an app-wide failure.
Critical 5 LogCritical Used for severe failures that require immediate attention, such as data loss scenarios or out of disk space.
None 6 Indicates that a logging category should not write any messages. This level is typically used to completely disable logging.

Logging providers

A logging provider is a component that receives log messages from the application and decides how and where to store or display these messages.

👉 Built-in logging providers

ASP.NET includes some registration providers as part of its shared framework, which are:

  • Console: Logs output to the console.
  • Debug: Writes log output by using the System.Diagnostics.Debug class.
  • EventSource: Writes to a cross-platform event source.
  • EventLog: Sends log output to the Windows Event Log. Unlike the other providers, the EventLog provider does not inherit the default non-provider settings. If EventLog log settings aren't specified, they default to LogLevel.Warning.

There are other registration providers provided by Microsoft that are not part of the shared framework. To use them, you must install them as extra nuget packages. These include:

  • Azure App Services: It is part of the Microsoft.Extensions.Logging.AzureAppServices NuGet package and writes logs to text files in the file system of an Azure App Service application and to a blob archive in an Azure Storage account.
  • Azure Application Insights: It is part of the Microsoft.Extensions.Logging.ApplicationInsights NuGet package and writes logs to Azure Application Insights, a service that monitors a web app and provides tools for querying and analyzing telemetry data.

👉 Third-party logging providers

There are various third-party logging tools that are compatible with ASP.NET, including:

Some third-party frameworks can perform semantic logging, also known as structured logging.

Semantic logging is an approach to logging that goes beyond simply logging text messages. Instead of writing unstructured log messages, it writes log events as well-defined data structures.

The advantage of semantic logging is that it makes it much easier to search, filter, and analyze logs. Because the data is structured, you can easily search for all login events by a specific user, or all events that occurred within a certain time range, without having to parse the text of each log message.

High-performance logging

When aiming for high-performance log registration, it is advisable to use LoggerMessage class. This class provides an efficient approach to create cached delegates that require fewer object allocations and lower computational overhead compared to logger extension methods like LogInformation and LogDebug.

LoggerMessage offers the following performance advantages over logger extension methods:

  • It avoids the "boxing conversion" of value types such as int to object, which is required by logger extension methods. This is achieved by using static Action fields and extension methods with strongly-typed parameters in the LoggerMessage approach.
  • It reduces the need to parse the message template (a named format string) with each log message write. LoggerMessage only requires parsing the template once during the message definition, saving processing time during actual log registration.
using Microsoft.Extensions.Logging;

public class MyClass
{
    private static readonly Action<ILogger, string, int, bool> _logMessage = LoggerMessage.Define<string, int, bool>(
        LogLevel.Information,
        new EventId(1001, "MyEvent"),
        "My message: {message}, {number}, {flag}");

    private readonly ILogger _logger;

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

    public void DoSomething()
    {
        var message = "Hello world";
        var number = 10;
        var flag = true;

        _logMessage(_logger, message, number, flag);
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the MyClass class uses the LoggerMessage class to define a cached delegate named _logMessage. The delegate takes three parameters: a string message, an integer number, and a boolean flag.

Inside the DoSomething() method, the _logMessage delegate is used to log a message using the _logger instance. The value of the message string, the number integer, and the flag boolean are passed to the delegate. The log message is formatted using the template specified in the delegate's definition.

This approach allows for avoiding "boxing conversion" of values and parsing the message template only during the definition of the _logMessage delegate, thus providing better performance compared to logger extension methods.

Conclusion

Logging is a key feature in software development that allows for easy troubleshooting and auditing in applications. ASP.NET provides powerful logging capabilities, including built-in and third-party logging providers, enabling you to configure, categorize, and analyze logs according to your specific needs. The semantic or structured logging approach offers easier log analysis, and for performance-critical applications, the LoggerMessage class enables efficient creation of cached delegates. Overall, good logging practices can significantly enhance an application's reliability, maintainability, and performance.

References

Top comments (4)

Collapse
 
instancemaster profile image
InstanceMaster

Great article! Please check out LogScope.NET library as an alternative logging API: github.com/devInstance/LogScope

Collapse
 
fabriziobagala profile image
Fabrizio Bagalà

I was not familiar with this library. I will add it among the third-party providers. Thanks for the suggestion!

Collapse
 
rasheedmozaffar profile image
Rasheed K Mozaffar

I was actually thinking about looking up an article or a video regarding this particular topic, then stumpled upon this post by accident 😃
Great one ❤️

Collapse
 
fabriziobagala profile image
Fabrizio Bagalà

I am glad! Good study 😉