摘录自:Link
为什么需要 覆写 默认的日志配置?
默认的,日志 仅写入 控制台 或者 调试窗口
- 有时 需要写入文件或数据库
- 有时 希望扩展日志记录的其他信息
更改 默认的日志配置 属于哪个层次?
ASP.NET Core 框架的层次,自底而上:
- Host
- Middleware
- Routing
- MVC\SignalR\gRPC\Blazor\Other
- WebAPI\Razor Pages
修改 日志的 配置 属于Host层
在哪里 更改 日志的默认配置?
ASP.NET Core 2.0 之前,日志 在
Startup.cs中配置
ASP.NET Core 2.0 之后,
Startup.cs慢慢简化。许多配置 被移动到Program.cs的WebHostBuilder
ASP.NET Core 2.0 之后,日志的配置 也被移动到
Program.cs的WebHostBuilder
Program.cs 变得 更通用
ASP.NET Core 3.1 之后,
Program.cs变得 更加通用
IHostBuilder最先创建 (引导启动的关键)- 通过
IHostBuilder,可以创建IWebHostBuilder - 用
IWebHostBuilder配置
public class Program {
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
});
}
ASP.NET Core 几乎允许 覆盖和自定义 所有内容
IWebHostBuilder有很多扩展方法,允许我们覆盖 各种 默认行为
如何修改 日志的默认配置?
覆盖 日志的默认设置,需要使用
ConfigureLogging方法
public class Program {
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => {
webBuilder
.ConfigureLogging( (hostingContext, logging) => {
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
})
.UseStartup<Startup>();
});
}
什么是 迷你API?
ASP.NET Core 6.0中,微软引入了 简化配置的 迷你API方法 (minimal API)
- 不使用
Startup.cs文件 - 而是将 所有配置 添加到
Program.cs文件 WebApplication.CreateBuilder()创建一个 builder- 在builder上搞配置
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
使用 迷你API方式 配置日志:
用 builder.Logging的
AddConfiguration()- 从 builder.
Configuration可以得到那个叫 Logging 的 section
- 从 builder.
AddConsole()AddDebug()即:在builder上,再加:
builder.Logging.AddConfiguration(builder.Configuration.GetSection("Logging"));
builder.Logging.AddConsole();
builder.Logging.AddDebug();
如何 使用 自定义的 日志框架
这里,还是用 迷你API的方式 配置日志: builder.
Logging的
ClearProviders():- 清除 之前添加的 所有日志框架 提供程序
AddProvider()- 参数是 一个自定义类 ColoredConsoleLoggerProvider
- 实现了接口
ILoggerProvider - 可以返回
ILogger - 构造函数的参数: 一个自定义类 ColoredConsoleLoggerConfiguration
- 实现了接口
- 参数是 一个自定义类 ColoredConsoleLoggerProvider
using LoggingSample;
builder.Logging.ClearProviders();
var config = new ColoredConsoleLoggerConfiguration
{
LogLevel = LogLevel.Information,
Color = ConsoleColor.Red
};
builder.Logging.AddProvider(new ColoredConsoleLoggerProvider(config));
public class ColoredConsoleLoggerConfiguration
{
public LogLevel LogLevel { get; set; } = LogLevel.Warning;
public int EventId { get; set; } = 0;
public ConsoleColor Color { get; set; } = ConsoleColor.Yellow;
}
public class ColoredConsoleLoggerProvider : ILoggerProvider
{
private readonly ColoredConsoleLoggerConfiguration _config;
private readonly ConcurrentDictionary<string, ColoredConsoleLogger> _loggers = new ConcurrentDictionary<string,ColoredConsoleLogger>();
public ColoredConsoleLoggerProvider (ColoredConsoleLoggerConfiguration config)
{
_config = config;
}
public ILogger CreateLogger(string categoryName)
{
return _loggers.GetOrAdd(categoryName,name => new ColoredConsoleLogger(name, _config));
}
public void Dispose()
{
_loggers.Clear();
}
}
public class ColoredConsoleLogger : ILogger
{
private static readonly object _lock = new Object();
private readonly string _name;
private readonly ColoredConsoleLoggerConfiguration _config;
public ColoredConsoleLogger(string name, ColoredConsoleLoggerConfiguration config)
{
_name = name;
_config = config;
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel == _config.LogLevel;
}
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception exception,
Func<TState, Exception, string> formatter
)
{
if (!IsEnabled(logLevel))
{
return;
}
lock (_lock)
{
if (_config.EventId == 0 || _config.EventId == eventId.Id)
{
var color = Console.ForegroundColor;
Console.ForegroundColor = _config.Color;
Console.Write($"{logLevel} - ");
Console.Write($"{eventId.Id} - {_name} - ");
Console.Write($"{formatter(state, exception)}n");
Console.ForegroundColor = color;
}
}
}
}
- 使用
lock是因为:控制台本身 并不是线程安全的,可能出现错误的着色
其实,用不着自己写日志框架,已经有许多优秀的第三方日志框架可用:
- ELMAH
- log4net
- NLog
如何 使用第三方日志框架 NLog
NLog是,最早的一款 可以用于ASP.NET Core的日志框架
NLog 提供了 一个日志记录 提供程序 插件。可以方便地插入ASP.NET Core
- 配置NLog: 添加一个
NLog.Config文件- 一般,将标准消息记录在一个日志文件中
- 将自定义消息记录在另一个文件中
- 引入NuGet包
dotnet add package NLog.Web.AspNetCore
3.将NLog和IWebHostBuilder结合
- 方式一:
.UseNLog()
Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => {
webBuilder.ConfigureLogging((hostingContext, logging) => {
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog()
.UseStartup<Startup>();
});
- 方式二:使用迷你API
- builder.
WebHost.UseNLog()
- builder.
using NLog.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.SetMinimumLevel(LogLevel.Trace);
builder.WebHost.UseNLog();