You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

9.7 KiB

sidebar_position title
14 Use the logs

Install logging

By default, a Blazor Server app is already set up to use logging.

With Blazor WebAssembly, we are now able to build Single Page Applications (SPAs) using C# and the ASP.NET Core framework. Coming from ASP.NET Core MVC, you may wonder what .NET features are available, limited, or not available when running in the browser. One of them is logging, which is a basic means for debugging in production environments and during development.

For a Blazor WASM application the installation of the Microsoft.Extensions.Logging.Configuration nuget will be required.

In the application settings file, provide the logging configuration. The logging configuration is loaded into Program.cs.

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

Similarly for Blazor WASM adding the Microsoft.Extensions.Logging.Configuration namespace and logging configuration to Program.cs will be required:

using Microsoft.Extensions.Logging;

...

builder.Logging.AddConfiguration(builder.Configuration.GetSection("Logging"));

Use the logs

To create logs, use an ILogger<TCategoryName> object from the ILogger<TCategoryName> DI.

The following example:

  • Creates an event logger, ILogger<CreateLog> , which uses a fully qualified log ILogger<CreateLog> of type CreateLog . The log category is a string associated with each log.
  • Calls each log level with the Log method.
@page "/logs"

<h3>CreateLog</h3>

<button @onclick="CreateLogs">Create logs</button>
using Microsoft.Extensions.Logging;

public partial class CreateLog
{
	[Inject]
	public ILogger<CreateLog> Logger { get; set; }

	private void CreateLogs()
	{
		var logLevels = Enum.GetValues(typeof(LogLevel)).Cast<LogLevel>();

		foreach (var logLevel in logLevels.Where(l => l != LogLevel.None))
		{
			Logger.Log(logLevel, $"Log message for the level: {logLevel}");
		}
	}
}

Here is the result after clicking the button:

Use the logs

Configuring logging

Logging configuration is usually provided by the Logging section of the appsettings.{Environment}.json files.

The following sample code appsettings.Development.json is generated by the web application templates:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

In the preceding JSON code:

  • The "Default", "Microsoft" and "Microsoft.Hosting.Lifetime" categories are specified.
  • The "Microsoft" category applies to all categories that start with "Microsoft". For example, this setting applies to the "Microsoft.AspNetCore.Routing.EndpointMiddleware" category.
  • The "Microsoft" category saves logs at the Warning level and above.
  • The "Microsoft.Hosting.Lifetime" category is more specific than the "Microsoft" category, so the "Microsoft.Hosting.Lifetime" category records logs at the Information level and above.

The Logging property can have different LogLevel and provider. LogLevel specifies the minimum LogLevel to record for the selected categories. In the preceding JSON, the Information & Warning levels of logging are specified. LogLevel indicates the severity of the log and ranges from 0 to 6:

Trace=0, Debug=1, Information=2, Warning=3, Error=4, Critical=5 and None=6.

When a LogLevel is specified, logging is enabled for messages at the specified level and above. In the preceding JSON, the Default category is logged for Information and later. For example, Information, Warning, Error and Critical messages are logged. If no LogLevel is specified, logging defaults to the Information level.

A provider property can specify a LogLevel property. LogLevel under a provider specifies logging levels for that provider, and overrides non-provider log settings.

Consider the following appsettings.json file:

{
  "Logging": {
    "LogLevel": { // All providers, LogLevel applies to all the enabled providers.
      "Default": "Error", // Default logging, Error and higher.
      "Microsoft": "Warning" // All Microsoft* categories, Warning and higher.
    },
    "Debug": { // Debug provider.
      "LogLevel": {
        "Default": "Information", // Overrides preceding LogLevel:Default setting.
        "Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category.
      }
    },
    "EventSource": { // EventSource provider
      "LogLevel": {
        "Default": "Warning" // All categories of EventSource provider.
      }
    }
  }
}

Settings in Logging.{providername}.LogLevel override settings in Logging.LogLevel. In the preceding JSON code, the default value of the Debug provider is Information:

Logging:Debug:LogLevel:Default:Information

How filter rules are applied

When creating an ILogger<TCategoryName> object, the ILoggerFactory object selects a single rule to apply to this event logging per provider. All messages written by an ILogger instance are filtered according to the selected rules. The most specific rule for each vendor and category pair is selected from the available rules.

The following algorithm is used for each provider when an ILogger object is created for a given category:

  • Select all rules that match the provider or its alias. If no match is found, select all rules with an empty provider.
  • From the result of the previous step, select the rules with the longest matching category prefix. If no match is found, select all rules that don't specify a category.
  • If multiple rules are selected, take the last.
  • If no rule is selected, use MinimumLevel.

Log level

The following table lists the values for LogLevel:

Log Level Value Method Description
Track 0 LogTrace Contains the most detailed messages. These messages may contain sensitive application data. These messages are disabled by default and should not be enabled in production.
Debug 1 LogDebug For debugging and development. Use with caution in production due to high volume.
Information 2 Log Information Tracks the general progress of the application. May have long term value.
Disclaimer 3 LogWarning For abnormal or unexpected events. Usually includes errors or conditions that do not cause the application to fail.
Error 4 LogError Provides information about errors and exceptions that cannot be handled. These messages indicate a failure in the current operation or request, not the entire application.
Review 5 LogCritical Provides information about failures that require immediate investigation. Examples: data loss, insufficient disk space.
None 6 Specifies that a logging category should write no messages.

In the previous table, the LogLevel is listed from lowest to highest severity level.

The first parameter of the logging method, LogLevel, indicates the severity of the log.

Instead of calling Log(LogLevel, ...), most developers call Log{LogLevel} extension methods. The Log{LogLevel} extension methods call the Log method specifying the LogLevel. For example, the following two logging calls are functionally equivalent and produce the same log:

var message = "My Log Message";

Logger.Log(LogLevel.Information, message);
Logger.LogInformation(message);

The following code creates Information and Warning logs:

var id = 10;

Logger.LogInformation("Getting item {Id}", id);

var todoItem = await _context.TodoItems.FindAsync(id);

if (todoItem == null)
{
	Logger.LogWarning("Get({Id}) NOT FOUND", id);
	return NotFound();
}

In the preceding code, the first argument to Log{LogLevel} is a message template containing placeholders for the argument values provided by the other method parameters.

Log message template

Each log API uses a message template. The latter may contain placeholders for which the arguments are provided. Use names, not numbers, for placeholders.

var id = 10;

Logger.LogInformation("Getting item {Id}", id);

var todoItem = await _context.TodoItems.FindAsync(id);

if (todoItem == null)
{
	Logger.LogWarning("Get({Id}) NOT FOUND", id);
	return NotFound();
}

The order of parameters, not their placeholder names, determines which parameters are used to provide placeholder values in log messages.

In the following code, the parameter names are out of sequence in the message template placeholders:

int apples = 1;
int pears = 2;
int bananas = 3;

Logger.LogInformation("Parameters: {pears}, {bananas}, {apples}", apples, pears, bananas);

However, parameters are assigned to placeholders in the following order: apples , pears , bananas .

The log message reflects the order of the parameters:

Parameters: 1, 2, 3

This approach allows logging providers to implement semantic or structured logging. The actual arguments, not just the formatted message template, are passed to the logging system. This allows logging providers to store parameter values as fields.

For example, consider the following logger method:

Logger.LogInformation("Getting item {Id} at {RequestTime}", id, DateTime.Now);

for example, when logging to Azure Table Storage:

  • Each Azure table entity can have ID and RequestTime properties.
  • Tables with properties simplify queries on logged data. For example, a query can find all logs in a given RequestTime range without having to parse the text message timeout.