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 logILogger<CreateLog>
of typeCreateLog
. 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:
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 theWarning
level and above. - The
"Microsoft.Hosting.Lifetime"
category is more specific than the"Microsoft"
category, so the"Microsoft.Hosting.Lifetime"
category records logs at theInformation
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
andRequestTime
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.