owned this note
owned this note
Published
Linked with GitHub
---
tags: 教材
title: Microsoft.Extensions.Logging
---
## 三個介面
[ILogger](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.ilogger?view=dotnet-plat-ext-3.1):紀錄日誌
[ILoggerProvider](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.iloggerprovider?view=dotnet-plat-ext-3.1):產生 ILogger 實例
[ILoggerFactory](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.iloggerfactory?view=dotnet-plat-ext-3.1):使用那些 ILoggerProvider
由 Microsoft.Extensions.Logging.Abstractions 和 Microsoft.Extensions.Logging 所提供
`Install-Package Microsoft.Extensions.Logging`
`Install-Package Microsoft.Extensions.Logging.Abstractions`
## 實例化範例
開始之前先來看個範例,以下的範例,
要先安裝`Install-Package Microsoft.Extensions.Logging.Console`
### .NET Framework
- 在 .NET Framework 沒有像 .NET Core 內建 DI Container,可以呼叫 LoggerFactory.Create 建立實例。
- builder.AddConsole():使用 Console LoggerProvider。
- factory.CreateLogger():Logger 實例。
- logger.LogInformation:寫入 Log,等級為 Information
```csharp=
var factory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
});
var logger = factory.CreateLogger<Form1>();
logger.LogInformation("Example log message");
```
### ASP.NET Core 3.1
- 可以使用 DI Container 的方式注入
- builder.AddConsole():使用 Console LoggerProvider
```csharp=
public class Program
{
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
.ConfigureLogging((context, builder) =>
{
builder.AddConsole();
});
}
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
}
```
- 在 Controller 就可以拿到 ILogger 實例
- logger.LogInformation:寫入 Log,等級為 Information
```csharp=
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
this._logger = logger;
}
[HttpGet]
public IActionResult Get()
{
...
this._logger.LogInformation(LogEvent.GenerateItem,"開始,訪問 WeatherForecast api");
}
}
```
## 6個層級
[LogLevel](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.loglevel?view=dotnet-plat-ext-3.1) 定義以及建議的使用方式如下:
| LogLevel | 值 | 擴充方法 | 描述 |
| ----------- | --- |:--------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Trace | 0 | [LogTrace](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.loggerextensions.logtrace?view=dotnet-plat-ext-3.1) | 追蹤:包含最詳細的訊息。 這些訊息可能包含敏感性應用程式資料。 這些訊息預設為停用,且不應在生產環境中啟用。 |
| Debug | 1 | [LogDebug](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.loggerextensions.logdebug?view=dotnet-plat-ext-3.1) | 偵錯:用於偵錯工具和開發。 請在生產環境中小心使用,因為有大量的數量。 |
| Information | 2 | [LogInformation](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.loggerextensions.loginformation?view=dotnet-plat-ext-3.1) | 資訊:追蹤應用程式的一般流程。 可能具有長期值。 |
| Warning | 3 | [LogWarning](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.loggerextensions.logwarning?view=dotnet-plat-ext-3.1) | 警告:針對異常或非預期的事件。 通常會包含不會導致應用程式失敗的錯誤或狀況。 |
| Error | 4 | [LogError](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.loggerextensions.logerror?view=dotnet-plat-ext-3.1) | 錯誤:發生無法處理的錯誤和例外狀況。 這些訊息表示目前的作業或要求失敗,而不是整個應用程式的失敗。 |
| Critical | 5 | [LogCritical](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.loggerextensions.logcritical?view=dotnet-plat-ext-3.1) | 嚴重:發生需要立即注意的失敗。 範例:資料遺失情況、磁碟空間不足。 |
| None | 6 | | 指定記錄類別不應寫入任何訊息。 |
- 如果未設定預設記錄層級,則預設的記錄層級值為 Information 。
ASP.NET Core 範例如下:
```csharp=
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Warning))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
```
> 參考
https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#log-level
## ILoggerFactory
以下的範例,要先安裝`Install-Package Microsoft.Extensions.Logging.Console`
- 在 .NET Framework 沒有像 ASP .NET Core 內建 DI Container,可以呼叫 LoggerFactory.Create 建立實例
```csharp=
var factory = LoggerFactory.Create(builder =>
{
builder.AddConsole()
;
});
var logger = factory.CreateLogger<Form1>();
logger.LogInformation("Example log message");
```
- ASP.NET Core 3.1 可以使用 DI Container 的方式注入
[Host.CreateDefaultBuilder](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.hosting.host.createdefaultbuilder?view=dotnet-plat-ext-3.1) 會注入下列 LoggerProvider
[主控台](https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#console)
[偵錯](https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#console)
[EventSource](https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#event-source)
[EventLog](https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#welog):僅限 Windows
為了演示,我仍然注入了 LoggerProvider
```csharp=
public class Program
{
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
.ConfigureLogging((context, builder) =>
{
builder.AddConsole()
;
});
}
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
}
```
在 Controller 即可取出 ILogger 實例
```csharp=
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
this._logger.LogInformation("訪問 /WeatherForecast");
///....
}
```
除了,預設 Controller 注入,我們也可以針對其他物件注入 ILogger
```csharp=
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRazorPages();
services.AddSingleton<IMyService>((container) =>
{
var logger = container.GetRequiredService<ILogger<MyService>>();
return new MyService() { Logger = logger };
});
}
```
> 參考
> https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#logging-providers
## ILoggerProvider
- 內建提供以下 LoggerProvider
Console:[Microsoft.Extensions.Logging.Console](https://www.nuget.org/packages/microsoft.extensions.logging.console/)
Debug:[Microsoft.Extensions.Logging.Debug](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Debug)
EventLog:[Microsoft.Extensions.Logging.EventLog](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventLog)
AzureAppServices:[Microsoft.Extensions.Logging.AzureAppServices](https://www.nuget.org/packages/Microsoft.Extensions.Logging.AzureAppServices)
EventSource:[Microsoft.Extensions.Logging.EventSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventSource/)
- 3rd LoggerProvider
支援 ASP.NET Core 的 Log 協力廠商
[elmah.io](https://www.nuget.org/packages/Elmah.Io.Extensions.Logging)
[Gelf](https://www.nuget.org/packages/Gelf.Extensions.Logging)
[JSNLog](https://www.nuget.org/packages/JSNLog.AspNetCore/)
KissLog.net
[Log4Net](Microsoft.Extensions.Logging.Log4Net.AspNetCore)
[Loggr](https://www.nuget.org/packages/Loggr.Extensions.Logging/)
[NLog](https://www.nuget.org/packages/NLog.Extensions.Logging/)
[PLogger](https://www.nuget.org/packages/InvertedSoftware.PLogger.Core/)
[Sentry](https://www.nuget.org/packages/Sentry.Extensions.Logging)
[Serilog](https://www.nuget.org/packages/Serilog.AspNetCore)
Stackdriver
> 參考
> https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#third-party-logging-providers
## ILogger
只需要一行程式,即可依照 LoggerProvider,寫入不同的目標
如下範例,注入了多個 LoggerProvider
```csharp=
public static IHostBuilder CreateHostBuilder(
string[] args) => Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging(logging =>
{
// clear default logging providers
logging.ClearProviders();
// add built-in providers manually, as needed
logging.AddConsole();
logging.AddDebug();
logging.AddEventLog();
logging.AddEventSourceLogger();
logging.AddTraceSource(sourceSwitchName);
});
```
### Log Message
1. Log() 方法要傳入 Level 參數
2. 擴充方法,方法名稱已經帶有 Level
```csharp=
// Log() 方法要帶有 Level
ILogger.Log(LogLevel.Information, "some text");
// 擴充方法,方法名稱已經帶有
ILogger.LogInformation("some text");
```
### Log 分類
ILogger 建立物件時,需要指定分類,分類的字串是任意的,慣例是使用類別名稱。
LoggerFactory.Create 使用範例如下:
```csharp=
var factory = LoggerFactory.Create(builder =>
{
builder.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("WindowsFormsApp1", LogLevel.Debug)
.AddConsole()
;
});
var logger = factory.CreateLogger<Form1>();
logger.LogInformation("Example log message");
```
ASP.NET Core 可以使用注入,最後,在建構函數改變自訂的分類名稱
```csharp=
public class ContactModel : PageModel
{
private readonly ILogger _logger;
public ContactModel(ILoggerFactory logger)
{
_logger = logger.CreateLogger("MyCategory");
}
public void OnGet()
{
_logger.LogInformation("GET Pages.ContactModel called.");
}
```
> 參考
> https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#log-category
### Log 範本
- 訊息範本可以包含預留變數,變數使用名稱而非數字
- 傳遞參數,可讓 LoggerProvider 執行語意結構化紀錄
```csharp=
_logger.LogInformation("Getting item {Id} at {RequestTime}", id, DateTime.Now);
```
> 參考
https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#log-message-template
### Scope
在非同的框架下,同一個流程,日誌內容會被散落在四處,這時後利用 [BeginScope](docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.ilogger.beginscope?view=dotnet-plat-ext-3.1) 可以讓我們的日誌比較好
- 內建支援的 LoggerProvider:
[Console](https://www.nuget.org/packages/microsoft.extensions.logging.console/)
[AzureAppServicesFile 和 AzureAppServicesBlob](https://docs.microsoft.com/zh-tw/dotnet/api/microsoft.extensions.logging.azureappservices.batchingloggeroptions.includescopes?view=dotnet-plat-ext-3.1#Microsoft_Extensions_Logging_AzureAppServices_BatchingLoggerOptions_IncludeScopes)
- 使用方式
在 BeginScope 調用關閉(IDisposable)前都屬於都一個範圍,可用 Using 包起來
```csharp=
[HttpGet]
public IActionResult Get()
{
using (this._logger.BeginScope($"Scope Id:{Guid.NewGuid()}"))
//using (this._logger.BeginScope("Scope Id:{id}", Guid.NewGuid().ToString())
{
this._logger.LogInformation("開始,訪問 WeatherForecast api");
this._logger.LogInformation("執行流程");
var random = new Random();
var result = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = random.Next(-20, 55),
Summary = Summaries[random.Next(Summaries.Length)]
})
.ToArray();
this._logger.LogInformation("結束流程");
return this.Ok(result);
}
}
```
最後再設定檔的 Console LoggerProvider 加入 "IncludeScopes": true
```json=
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
"Console": {
"IncludeScopes": true,// <= 這裡
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning"
}
}
},
"AllowedHosts": "*"
}
```
執行結果:
![](https://i.imgur.com/K6fauTR.png)
> 參考
> https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#log-scopes
### 事件識別碼
識別碼用來建立日誌的關聯性,有些 LoggerProvider 有提供識別碼篩選
先建立識別碼。如下:
```csharp=
public class LogEvent
{
public const int GenerateItem = 1000;
public const int ListItem = 1001;
public const int GetItem = 1002;
public const int InsertItem = 1003;
public const int UpdateItem = 1004;
public const int DeleteItem = 1005;
public const int TestItem = 3000;
public const int GetItemNotFound = 4000;
public const int UpdateItemNotFound = 4001;
}
```
```csharp=
[HttpGet]
public IActionResult Get()
{
//using (this._logger.BeginScope($"Scope Id:{Guid.NewGuid()}"))
using (this._logger.BeginScope("Scope Id:{id}", Guid.NewGuid()))
{
this._logger.LogInformation(LogEvent.GenerateItem,"開始,訪問 WeatherForecast api");
this._logger.LogInformation(LogEvent.TestItem,"執行流程");
var random = new Random();
var result = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = random.Next(-20, 55),
Summary = Summaries[random.Next(Summaries.Length)]
})
.ToArray();
this._logger.LogInformation(LogEvent.GenerateItem,"結束流程");
return this.Ok(result);
}
}
```
執行結果:
Console LoggerProvider 就會在類別後面加上 [識別碼] WebApiNetCore31.Controllers.WeatherForecastController[1000]
![](https://i.imgur.com/ZmfKnr4.png)
>參考
>https://docs.microsoft.com/zh-tw/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#log-event-id
## Config
ASP.NET Core 的預設專案範本一建立就會產生 appsettings.json、appsettings.Development.json 內容如下:
```json=
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
```
上述設定,LoggerProvider 會依照 Namsespace 和 LogLevel 過濾出需要記錄的日誌,當指定某一 Level 時,代表該等級以上的 Log 都會被記錄下來
- Logging:所有的 LoggerProvider,套用此設定
- Default:預設,套用 Information Level
- Microsoft:"Microsoft" 開頭的命名空間,套用 Warning Level
- Microsoft.Hosting.Lifetime:比類別更明確 "Microsoft",所以 "Microsoft.Hosting.Lifetime" 的等級為 Information
- 特定分類覆蓋 Default 分類
- Level 高的覆蓋低的
- 若要隱藏所有的日誌則指定 None
ASP.NET Core 範例如下:
```csharp=
public class Program
{
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
.ConfigureLogging((context, builder) =>
{
builder.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("WindowsFormsApp1", LogLevel.Debug)
.AddConfiguration(context.Configuration.GetSection("Logging"))
.AddConsole()
;
});
}
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
}
```
## Filer 函數
當 Config 之外,透過 Filter 做更多的設定
ASP.NET Core 範例如下:
```csharp=
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddFilter((provider, category, logLevel) =>
{
if (provider.Contains("ConsoleLoggerProvider")
&& category.Contains("Controller")
&& logLevel >= LogLevel.Information)
{
return true;
}
else if (provider.Contains("ConsoleLoggerProvider")
&& category.Contains("Microsoft")
&& logLevel >= LogLevel.Information)
{
return true;
}
else
{
return false;
}
});
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
```
:::info
一般來說,記錄層級應指定于設定中,而不是程式碼。
:::