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.

263 lines
9.7 KiB

---
sidebar_position: 14
title: 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`.
```json title="wwwroot/appsettings.json"
{
"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:
```csharp title="Program.cs"
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.
```csharp title="Pages/CreateLog.razor"
@page "/logs"
<h3>CreateLog</h3>
<button @onclick="CreateLogs">Create logs</button>
```
```csharp title="Pages/CreateLog.razor.cs"
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](/img/logs.png)
## 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:
```json title="appsettings.Development.json"
{
"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:
```json title="appsettings.json"
{
"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:
```csharp
var message = "My Log Message";
Logger.Log(LogLevel.Information, message);
Logger.LogInformation(message);
```
The following code creates `Information` and `Warning` logs:
```csharp
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.
```csharp
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:
```csharp
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:
```csharp
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.