Default Logging in ASP.NET Core Web API

Default Logging in ASP.NET Core Web API

In this article, I will discuss How to Implement Default Logging in ASP.NET Core Web API Application with Examples. Please read our previous article discussing the basic concepts of Logging in ASP.NET Core Web API Application. At the end of this article, you will understand the following pointers:

  1. What is Default Logging in ASP.NET Core Web API?
  2. Default Logging Configuration in ASP.NET Core Web API
  3. Understanding Different Methods of ILogger<T> in ASP.NET Core Web API
  4. Log Levels in ASP.NET Core Web API
  5. Configuring Log Levels to Show All Types of Logs
  6. Log Level Configurations in the Program.cs class file
  7. Importance of Choosing the Right Log Level
What is Default Logging in ASP.NET Core Web API?

Default Logging in the ASP.NET Core Web API is enabled through the Microsoft.Extensions.Logging library, an extensible logging mechanism integrated into the .NET Core framework. This allows for logging to various outputs such as the console, debug window, and even external data stores or logging services.

Here is how to set up and use default logging in an ASP.NET Core Web API project. First, create a new ASP.NET Core Web API Project named LoggingDemo.

Default Logging Configuration in ASP.NET Core Web API

The Configuration settings for logging can be specified in the appsettings.json file. For example, in appsettings.json, you can specify the minimum logging level for different categories as follows. The following JSON code snippet is the configuration for the logging behavior of an ASP.NET Core Web API application, defined within the appsettings.json file. This file is a standard part of ASP.NET Core projects and configures settings, including logging, connection strings, and other application settings.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information", // Set the default log level to Trace
      "Microsoft": "Warning", // You might want to limit framework logs to warnings and above
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}
Understanding the above JSON Code:

Here’s a breakdown of what each part of this configuration means:

  • “Logging”: This is the root node for logging configurations. It specifies that the settings contained within are related to how the application logs information.
  • “LogLevel”: Under the Logging node, LogLevel specifies the minimum level of log messages that the application will write for various categories. Log levels indicate the severity of the messages logged, and ASP.NET Core supports several log levels, such as Trace, Debug, Information, Warning, Error, Critical, and None.
  • “Default”: “Information”: This setting specifies the application’s default log level. In this case, “Information” and higher severity messages (Warning, Error, Critical) will be logged. “Information” level logs are useful for tracking an application’s flow during normal operation.
  • “Microsoft”: “Warning”: This key specifically controls the logging level for logs originating from ASP.NET Core framework components. Setting this to Warning means only warnings, errors, and critical logs from the framework will be shown. This can help reduce noise from the framework’s internal operation logs when you are not interested in debugging the framework itself.
  • “Microsoft.AspNetCore”: “Warning”: The Microsoft.AspNetCore key can be particularly useful when you want to adjust the logging level for ASP.NET Core-related activities (such as routing, model binding, middleware operations, etc.) without affecting the logging levels of other parts of the .NET runtime or your application.
Setting up in Program.cs Class file

In .NET 6 or later, logging is configured in the Program.cs file as part of building the web application host. The default setup automatically adds logging services to the application container, but you can customize this configuration as needed. Here, we specify the log to be displayed in the Console and Debug windows. Here, you can specify both or anyone as per your requirement.

// Configure logging
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddDebug();

Here,

  • builder.Logging.ClearProviders(): The ClearProviders method removes all logging providers from the application. Logging providers are responsible for recording log messages to various outputs (e.g., console, files, external services). Clearing them gives you full control over which logging providers are used in your application.
  • builder.Logging.AddConsole(): This method adds a logging provider that outputs log messages to the console. It’s useful during development, as it lets you see log messages directly in the terminal or command prompt window where you’re running your application.
  • builder.Logging.AddDebug(): The AddDebug method adds a logging provider that sends log messages to the debug output window in Visual Studio or other debuggers attached to the process. This is particularly useful for debugging applications because it lets you see log messages in real time while navigating code.
Using ILogger

In your controllers or other services, you can inject ILogger<T> to log messages where T is the type of your class. This allows you to write log messages that include information about the source of the log entry.

using Microsoft.AspNetCore.Mvc;

namespace LoggingDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TestController : ControllerBase
    {
        private readonly ILogger<TestController> _logger;

        public TestController(ILogger<TestController> logger)
        {
            _logger = logger;
            _logger.LogInformation("TestController Started");
        }

        [HttpGet]
        public IActionResult Get()
        {
            _logger.LogInformation("Executing TestController.Get Method");
            return Ok();
        }
    }
}

As you can see in the above code, we have added two log information, one within the constructor and one within the Get action method of the Controller. Now, run the application and access the above Get endpoint, and it should log the information as expected.

Checking the Console Window: After invoking the above endpoint, verify the Console window, and you should see the following message:

How to Implement Default Logging in ASP.NET Core Web API Application with Examples

Checking the Debug Window: Now, to verify the Debug window, please select Debug => Windows => Output option from the context menu, and verify the log messages as shown in the below image:

How to Implement Default Logging in ASP.NET Core Web API Application with Examples

Understanding Different Methods of ILogger<T> in ASP.NET Core Web API

In ASP.NET Core, ILogger<T> is an interface provided by Microsoft.Extensions.Logging namespace. The generic parameter T typically represents the class into which the logger is injected. This allows the logging framework to automatically include the class name in the log messages, making it easier to track where a log message originated.

ILogger<T> offers several methods for logging, each corresponding to a level of severity or importance. Here’s an overview of the different logging methods available:

LogTrace(string message, params object[] args)
  • Level: Trace
  • Usage: This method logs the most detailed information, often useful only for debugging, such as entering or leaving a method and the values of variables.
LogDebug(string message, params object[] args)
  • Level: Debug
  • Usage: Debug-level logging is slightly less detailed than a trace. It’s used for information that may be useful for debugging but does not need to be as granular as trace messages.
LogInformation(string message, params object[] args)
  • Level: Information
  • Usage: This method is used to log informational messages highlighting the application’s general flow. These messages should be informative and not include any sensitive information.
LogWarning(string message, params object[] args)
  • Level: Warning
  • Usage: Warning-level logging indicates that something unexpected happened in the application or there’s a potential problem in the future, but the application is still working as expected.
LogError(string message, params object[] args)
  • Level: Error
  • Usage: This method is used when the application encounters a more serious problem. An error should be logged when the current operation or request fails, but the application can still continue running.
LogCritical(string message, params object[] args)
  • Level: Critical
  • Usage: Critical-level logging indicates very severe problems or crashes in the application. These are problems that require immediate attention, such as a critical system failure.

Additional Methods: Besides these level-specific methods, ILogger<T> also provides a generic Log method that allows specifying the log level as a parameter, giving you more control over the log level at runtime.

Example to Understand the above Methods:

The following example shows how to use the various logging methods (LogTrace, LogDebug, LogInformation, LogWarning, LogError, LogCritical, Log) within an ASP.NET Core Web API Controller. This example demonstrates how you might log different levels of information based on the execution path and events within a specific controller action:

using Microsoft.AspNetCore.Mvc;

namespace LoggingDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TestController : ControllerBase
    {
        private readonly ILogger<TestController> _logger;

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

        [HttpGet]
        public IActionResult Get()
        {
            _logger.LogTrace("Trace: Entering Get method");

            try
            {
                _logger.LogDebug("Debug: Starting processing request in Get method");

                // Simulate some work
                _logger.LogInformation("Information: Performing some operations");

                if (DateTime.Now.Millisecond % 2 == 0) // Random condition for demonstration
                {
                    _logger.LogWarning("Warning: The operation resulted in an expected but non-critical issue");
                }
                else
                {
                    // Simulate an error
                    throw new InvalidOperationException("An error occurred during the operation");
                }

                _logger.LogInformation("Information: Successfully processed request in Get method");
                _logger.Log(LogLevel.Information, "Information: Successfully processed request in Get method");
                return Ok("Success");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error: An error occurred while processing the request in Get method");
                _logger.LogCritical(ex, "Critical: This error is critical and needs immediate attention");

                return StatusCode(500, "An error occurred while processing your request");
            }
            finally
            {
                _logger.LogTrace("Trace: Exiting Get method");
            }
        }
    }
}

In this example:

  • LogTrace is used at the start and end of the Get method to log the method’s entry and exit. Trace logs are usually turned off in production environments.
  • LogDebug is used to log debug-level information right after starting the process. Debug logs are useful for developers while debugging the application.
  • LogInformation logs informational messages that highlight the general flow of the method. It’s used both at the start of some operations and upon successful completion.
  • LogWarning is used to log a warning message inside a conditional block, indicating a potential issue that is not critical but should be noted.
  • LogError is used within the catch block to log exceptions that prevent the operation from completing successfully.
  • LogCritical emphasizes the severity of the error caught in the catch block, indicating a severe problem that requires immediate attention.

Now, run the application and access the above endpoint. You will see the following in the command prompt.

Different Methods of ILogger<T> in ASP.NET Core Web API

As you can see, we are getting the information, errors, and Critical log messages. But we are not getting the Trace and Debug messages. To understand the reason, we need to understand the Log Levels.

Log Levels in ASP.NET Core Web API:

ASP.NET Core supports various log levels, including Trace, Debug, Information, Warning, Error, Critical, and None. The level you choose determines the importance of the message and how the logging framework and its providers handle it. If you go to the LogLevel enum, then you will see the following:

Log Levels in ASP.NET Core Web API

Here’s an overview of each log level:

Trace
  • Severity: Very Low
  • Description: Trace is the most verbose logging level, providing detailed information about the application’s behavior. It’s typically used for diagnosing complex issues and tracing the application’s execution flow. Trace logs might include detailed state information, sequence of events, and other insights useful during development or debugging.
  • Use Cases: Debugging, detailed application flow tracing.
Debug
  • Severity: Low
  • Description: Debug logs are less verbose than trace logs but provide detailed information that is useful in development and debugging scenarios. They might include information about application execution, decisions made by the application logic, and more.
  • Use Cases: Development, debugging, and providing insight into application behavior.
Information
  • Severity: Normal
  • Description: Information logs track the general flow of the application. They should be useful during development and production, providing insight into the application’s normal operations.
  • Use Cases: Tracking application flow, key operations, startup and shutdown events.
Warning
  • Severity: Medium
  • Description: Warning logs indicate that something unexpected happened in the application, a problem, or a situation that might lead to a future error. However, the application can still continue its operation. Warnings often highlight issues that should be investigated but aren’t critical.
  • Use Cases: Potential issues, unexpected events, degraded operation conditions.
Error
  • Severity: High
  • Description: Error logs signify a failure that occurred during the application’s current operation or request. An error usually affects the operation being performed but doesn’t necessarily crash the application. It’s a signal that something went wrong that needs attention and correction.
  • Use Cases: Operation failures are exceptions that are handled but disrupt normal operations.
Critical
  • Severity: Very High
  • Description: Critical logs indicate a severe problem that has caused a significant failure in the application. This level is reserved for errors that may cause the application to crash or require immediate attention.
  • Use Cases: Fatal errors, application crashes, critical system stability conditions.
None
  • Severity: N/A
  • Description: The None level is not used for logging but can be used in configuration to disable logging. No logging messages are written at all when set, effectively silencing the logging system.
  • Use Cases: Disabling logging.
Configuring Log Levels to Show All Types of Logs

Log levels are typically configured in the appsettings.json file or programmatically within the application’s startup code. Now, if you want to display all types of logs, we need to set the lowest log level in the configuration file. So, modify the appsettings.json file as follows:

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace", // Set the default log level to Trace
      "Microsoft": "Warning", // You might want to limit framework logs to warnings and above
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

After the above changes, if you are still not getting the log messages as expected, there might be a few areas to check and ensure everything is configured correctly.

ASP.NET Core supports environment-specific configuration files, such as appsettings.Development.json, appsettings.Production.json, etc. When running your application, it picks up the configuration settings from the file that matches the current environment. Ensure the logging level is set to Trace in the correct environment-specific configuration file. For example, if you’re running in development mode, make sure appsettings.Development.json contains the appropriate logging level settings as follows:

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

In our example, set the environment as Development and run the application, and this time, you should see the log messages as expected, as shown in the image below:

Configuring Log Levels to Show All Types of Logs

Viewing Trace and Debug Logs
  • During Development: If you’re running your application locally, you can see these logs in the console window from which you run your application. The visibility of trace and debug logs depends on the logging configuration, as mentioned.
  • In Production: For production environments, you should direct logs to more durable stores like files, databases, or logging services, considering the verbosity of trace and debug logs. Tools like Serilog or NLog can be configured to handle this efficiently.
Log Level Configurations in the Program.cs class file

In ASP.NET Core Web API applications, especially those using .NET 6 or later with the minimal hosting model, you can configure log levels directly in the Program.cs class file. This approach allows you to programmatically set up logging levels and providers, allowing you to adjust logging according to the environment or specific requirements that might not be as easily specified in the appsettings.json files.

Here’s how to set the log-level configurations in the Program.cs. To configure log levels, you can use the Logging property on the builder object. Here’s an example where we configure the log levels programmatically:

// Configure logging levels
builder.Logging.ClearProviders(); // Optional: Clears default providers
builder.Logging.AddConsole(); // Adds console logging
builder.Logging.AddDebug(); // Adds Debug window logging in Visual Studio

// Set specific log levels
builder.Logging.SetMinimumLevel(LogLevel.Information); // Global minimum level
builder.Logging.AddFilter("Microsoft", LogLevel.Warning); // For Microsoft.* namespaces
builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning); // For ASP.NET Core
builder.Logging.AddFilter("System", LogLevel.Warning); // For System.* namespaces
builder.Logging.AddFilter("YourApp.Namespace", LogLevel.Trace); // For your app's namespace
Explanation
  • ClearProviders(): This method clears all the logging providers that were added by default. It’s optional and can be useful if you want to have full control over which logging providers are being used.
  • AddConsole(), AddDebug(): These methods add console and debug logging providers, respectively. You can add other providers as needed, such as AddEventLog(), AddEventSourceLogger(), etc.
  • SetMinimumLevel(): This method sets the global minimum log level for the application. Only logs at this level and higher will be included.
  • AddFilter(): This method allows you to specify log levels for specific categories or namespaces. It’s very flexible, letting you define different log levels for different parts of your application or dependencies.

Let’s modify the Test controller to demonstrate how to use the configured logging levels within an ASP.NET Core Web API application. This controller will include logging examples at different levels according to the configurations set programmatically in Program.cs.

using Microsoft.AspNetCore.Mvc;

namespace LoggingDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TestController : ControllerBase
    {
        private readonly ILogger<TestController> _logger;

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

        [HttpGet]
        public IActionResult Get()
        {
            _logger.LogTrace("This is a Trace log, the most detailed information.");
            _logger.LogDebug("This is a Debug log, useful for debugging.");
            _logger.LogInformation("This is an Information log, general info about app flow.");
            _logger.LogWarning("This is a Warning log, indicating a potential issue.");
            _logger.LogError("This is an Error log, indicating a failure in the current operation.");
            _logger.LogCritical("This is a Critical log, indicating a serious failure in the application.");

            return Ok("Check your logs to see the different logging levels in action!");
        }
    }
}

The controller’s Get method demonstrates the use of various log-level methods (LogTrace, LogDebug, etc.) to log messages at different severities. The visibility of these logs in the output will depend on the logging configurations set in Program.cs. So, when you run the application and access the above endpoint, then it will log the messages as follows:

Log Level Configurations in the Program.cs class file

Considerations for Programmatic Log Configuration
  • Environment-Specific Configuration: You might want different log levels for development, testing, and production environments. Use environment variables or conditional checks to adjust the logging configuration based on the environment.
  • Performance and Security: Be mindful of the log levels used, especially in production. Higher log levels like Debug or Trace can impact performance and potentially expose sensitive information.
  • Dynamic Configuration: While setting log levels in the Program.cs provides a programmatic approach. Remember that changes require recompilation. For dynamic configurations that can be changed without redeploying the application, consider using appsettings.json or other configuration sources.
Importance of Choosing the Right Log Level

Selecting the appropriate log level is crucial for effective logging. Too verbose (Trace or Debug) in a production environment can lead to performance issues and log noise, making it hard to identify real issues. On the other hand, setting the log level too high might miss important information that could help diagnose problems.

Storing logs in a text file in an ASP.NET Core application can be achieved using third-party logging providers like Serilog, Log4Net, or NLog, as the default logging provider does not include a file logger. Serilog, Log4Net, and NLog are popular choices for logging in .NET applications and offer a wide range of features, including the ability to log to various targets such as files, databases, and more.

In the next article, I will discuss how to Implement Logging using Serilog in an ASP.NET Core Web API Application with Examples. In this article, I explain how to Implement Default Logging in an ASP.NET Core Web API Application with Examples. I hope you enjoy this article, How to Implement Default Logging in an ASP.NET Core Web API.

Leave a Reply

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