在默认日志级别,Blazor项目中默认提供如下日志记录提供程序:
在服务器上(Blazor Server),日志记录仅发生 在 LogLevel.Information
或更高级别的 Development
环境中的服务器端 .NET 控制台。
在客户端上(Blazor WebAssembly),日志记录仅发生 在 LogLevel.Information
或更高级别的客户端浏览器开发人员工具控制台。
Razor组件日志记录
要在组件中使用日志记录,可以通过注入ILogger<T>
或者ILoggerFactory
来实现。
ILogger<T>
示例
csharp
@page "/"
@inject ILogger<Home> Logger
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
@code{
protected override void OnInitialized(){
//这是服务端的组件
Logger.LogWarning("OKK");
}
}
ILoggerFactory
示例
csharp
@page "/counter"
@rendermode InteractiveAuto
@inject ILoggerFactory LoggerFactory
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
//这里用的客户端的组件
LoggerFactory.CreateLogger<Counter>().LogWarning("OKK");
}
}
客户端日志
对于客户端,并非支持所有ASP.NET Core的日志记录功能。例如,客户端组件无法访问客户端的文件系统或网络,因此无法将日志写入客户端的物理或网络存储。
一、设置日志等级
对于服务端项目的日志配置,默认情况下,可以在项目的appsettings.json
和appsettings.Development.json
文件中进行配置。
而在客户端项目中,要进行日志最低等级的配置,需要在Program.cs
中,使用WebAssemblyHostBuilder.Logging
属性进行日志的设置。
日志级别
- Trace:0,包含最详细消息的日志,不建议在生产环境下使用此等级。
- Debug:1,在开发期间用于交互式调查的日志。这些日志应该主要包含对调试有用的信息,没有长期价值。
- Information:2,跟踪应用的常规流,可能具有长期值。
- Warning:3,突出显示应用程序流中异常或意外事件,但不会导致应用程序执行停止的日志。
- Error:4,突出显示由于故障而停止当前执行流的日志。这些应该表明当前活动中的故障,而不是应用程序范围的故障。
- Critical:5,描述不可恢复的应用程序或系统崩溃,或需要立即注意的灾难性故障的日志。
- None:6,不进行任何日志记录。
示例-将日志最低等级设置为Warning-Program.cs
csharp
......
//设置日志级别
builder.Logging.SetMinimumLevel(LogLevel.Warning);
......
二、客户端Program.cs中输出日志
要在客户端的Program.cs
中输出日志,可以使用WebAssemblyHost
的服务容器中获取日志工厂ILoggerFactory
从而生成日志对象。
- 需要注意的是,只有在加载首次加载客户端组件时,才会运行
Program
中的代码。
Program.cs
csharp
var builder = WebAssemblyHostBuilder.CreateDefault(args);
var host = builder.Build();
var logger = host.Services.GetRequiredService<ILoggerFactory>()
.CreateLogger<Program>();
logger.LogInformation("Logged after the app is built in the Program file.");
await builder.Build().RunAsync();
三、日志类别
客户端同样支持日志类别,在创建 ILogger
对象时,需要指定日志类别,可以以下几种类别指定方式:
ILogger<T>
:在注入ILogger
接口时,通过泛型T
来指定,这种方式需要使用已存在的类型,然后会自动使用T
类型的完整空间命名来作为日志类别。CreateLogger<T>()
:ILoggerFactory
的方法,创建ILogger<T>
日志对象。CreateLogger(className)
:ILoggerFactory
的方法,创建ILogger
日志对象,这里的className
可以随便指定,不需要使用存在的类型名称。
示例
csharp
@page "/counter"
@rendermode InteractiveAuto
@inject ILogger<Counter> Logger
@inject ILoggerFactory LoggerFactory
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
LoggerFactory.CreateLogger("MyLogger").LogWarning("OKK");
Logger.LogWarning("OKK");
}
}
四、日志事件ID
Blazor客户端侧同样支持日志事件ID,每个日志都可以指定一个事件ID,一般会将所有日志事件ID作为常量封装到一个类中来使用。
LogEvent.cs
jsx
public class LogEvent
{
public const int Event1 = 1000;
public const int Event2 = 1001;
}
Counter.razor
csharp
@page "/counter"
@rendermode InteractiveAuto
@inject ILogger<Counter> Logger
......
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
Logger.LogInformation(LogEvent.Event1, "Someone has clicked me!");
Logger.LogWarning(LogEvent.Event2, "Someone has clicked me!");
}
}
五、日志异常参数
Blazor客户端侧支持日志异常参数的使用。
Counter.razor
csharp
@page "/counter"
@rendermode InteractiveAuto
@inject ILogger<Counter> Logger
......
@code {
private int currentCount = 0;
private void IncrementCount()
{
try
{
currentCount++;
throw new OperationCanceledException("Skip 3");
}
catch (Exception ex)
{
Logger.LogInformation(ex, "Exception (currentCount: {Count})!", currentCount);
}
}
}
六、日志筛选函数
指定日志类别与日志级别
在客户端如果希望只输出指定的日志类别和日志级别,可以通过在Program.cs
中使用builder.Logging.AddFilter
方法来添加过滤器。
Program.cs
csharp
......
//表示只记录日志类别为MyLoggerClass且日志级别为LogLevel.Information的日志
builder.Logging.AddFilter((provider, category, logLevel)=> category!.Equals("MyLoggerClass") && logLevel == LogLevel.Information);
......
Counter.razor
csharp
@page "/counter"
@rendermode InteractiveAuto
@inject ILoggerFactory LoggerFactory
......
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
ILogger _logger = LoggerFactory.CreateLogger("MyLoggerClass");
_logger.LogInformation("Information");
_logger.LogWarning("Warning");
}
}
七、身份验证日志记录
要开启身份验证的日志记录,可以有如下两种方法:
通过配置文件设置
csharp
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.Components.WebAssembly.Authentication": "Debug"
}
}
通过在Program.cs
中添加过滤器
csharp
builder.Logging.AddFilter("Microsoft.AspNetCore.Components.WebAssembly.Authentication", LogLevel.Debug);
八、自定义记录器提供程序
有时可能会遇到需要自己定义日志提供程序的需求,要实现自定义的日志提供程序,具体需要进行如下步骤:
创建日志级别字典
csharp
using Microsoft.Extensions.Logging;
public class CustomLoggerConfiguration
{
public int EventId { get; set; }
public Dictionary<LogLevel, LogFormat> LogLevels { get; set; } =
new()
{
[LogLevel.Information] = LogFormat.Short,
[LogLevel.Warning] = LogFormat.Short,
[LogLevel.Error] = LogFormat.Long
};
public enum LogFormat
{
Short,
Long
}
}
实现ILogger
接口,自定义日志提供程序
csharp
public sealed class CustomLogger : ILogger
{
private readonly string name;
private readonly Func<CustomLoggerConfiguration> getCurrentConfig;
public CustomLogger(
string name,
Func<CustomLoggerConfiguration> getCurrentConfig) =>
(this.name, this.getCurrentConfig) = (name, getCurrentConfig);
public IDisposable BeginScope<TState>(TState state) => default!;
public bool IsEnabled(LogLevel logLevel) =>
getCurrentConfig().LogLevels.ContainsKey(logLevel);
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
CustomLoggerConfiguration config = getCurrentConfig();
if (config.EventId == 0 || config.EventId == eventId.Id)
{
switch (config.LogLevels[logLevel])
{
case LogFormat.Short:
Console.WriteLine($"{name}: {formatter(state, exception)}");
break;
case LogFormat.Long:
Console.WriteLine($"[{eventId.Id, 2}: {logLevel, -12}] {name} - {formatter(state, exception)}");
break;
default:
// No-op
break;
}
}
}
}
实现自定义日志提供程序的配置类
csharp
using System.Collections.Concurrent;
using Microsoft.Extensions.Options;
[ProviderAlias("CustomLog")]
public sealed class CustomLoggerProvider : ILoggerProvider
{
private readonly IDisposable onChangeToken;
private CustomLoggerConfiguration config;
private readonly ConcurrentDictionary<string, CustomLogger> loggers =
new(StringComparer.OrdinalIgnoreCase);
public CustomLoggerProvider(
IOptionsMonitor<CustomLoggerConfiguration> config)
{
this.config = config.CurrentValue;
onChangeToken = config.OnChange(updatedConfig => this.config = updatedConfig);
}
public ILogger CreateLogger(string categoryName) =>
loggers.GetOrAdd(categoryName, name => new CustomLogger(name, GetCurrentConfig));
private CustomLoggerConfiguration GetCurrentConfig() => config;
public void Dispose()
{
loggers.Clear();
onChangeToken.Dispose();
}
}
给ILoggingBuilder
添加扩展方法
csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Configuration;
public static class CustomLoggerExtensions
{
public static ILoggingBuilder AddCustomLogger(
this ILoggingBuilder builder)
{
builder.AddConfiguration();
builder.Services.TryAddEnumerable(
ServiceDescriptor.Singleton<ILoggerProvider, CustomLoggerProvider>());
LoggerProviderOptions.RegisterProviderOptions
<CustomLoggerConfiguration, CustomLoggerProvider>(builder.Services);
return builder;
}
}
在Program.cs
中,添加日志提供程序。
csharp
builder.Logging.ClearProviders().AddCustomLogger();
使用第三方日志提供程序
这里以NLog的使用为例,由于浏览器存在访问权限等原因,这里只在服务端(Blazor Server)上使用。
一、安装NLog包
要在 ASP.NET Core 6 中使用 NLog,首先要安装 NLog 的扩展包,然后再进行一些基本的配置,就可以实现 NLog 与.NET Core 6 的集成了。
首先到Nuget中,下载对应的依赖库:
- 选择NLog.Extensions.Logging程序包,这个是微软参与开发的插件,也是微软官方网站上推荐的,兼容性也最好。
二、添加配置文件
NLog包安装完成之后,还需要配置才可使用,NLog使用的是NLog.config配置文件。
在项目中填加新项,选择Web配置文件,命名为NLog.config。
NLog.config
xml
<?xml version="1.0" encoding="utf-8"?>
<nlog
xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Warn"
internalLogFile="nlog.txt">
<targets>
<target xsi:type="File" name="allfile" fileName="nlog-all-${shortdate}.log" layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
<target xsi:type="File" name="ownFile-web" fileName="nlog-own-${shortdate}.log" layout="${longdate}|${logger}|${uppercase:${level}}| ${message} ${exception}"/>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="allfile" />
<logger name="Microsoft.*" minlevel="Trace" final="true" />
<logger name="*" minlevel="Trace" writeTo="ownFile-web" />
</rules>
</nlog>
三、注册NLog
NLog的包和配置文件完成之后,可以在Program
类中注册NLog日志提供程序。
NLog要使用ILoggerFactory
来提供注入服务,这里我们在统一的Program
类中注册NLog。
AddNLog([string path])
:ILoggingBuilder
的扩展方法,为Blzor框架添加NLog日志提供程序。
Program.cs
csharp
......
//清除掉所有的日志服务
builder.Logging.ClearProviders();
//添加NLog日志服务
builder.Logging.AddNLog();
......
这里试了一下,如果不清除掉所有的日志服务,直接添加NLog服务,可以保留其他日志提供程序的日志记录。
四、使用NLog
Home.razor
csharp
@page "/"
@inject ILoggerFactory LoggerFactory
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
@code{
protected override void OnInitialized(){
ILogger _logger = LoggerFactory.CreateLogger<Home>();
_logger.LogInformation("Information");
_logger.LogWarning("Warning");
}
}