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
263 lines
9.7 KiB
![]()
2 years ago
|
---
|
||
|
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:
|
||
|
|
||
|

|
||
|
|
||
|
## 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.
|