ASP.NET Core日志系统完全指南:基于practical-aspnetcore的6个场景
你是否还在为ASP.NET Core应用中的日志配置感到困惑?本文将通过practical-aspnetcore项目中的6个实战场景,带你从入门到精通日志系统的配置与优化。读完本文,你将掌握基础日志记录、日志过滤、结构化日志输出、高性能日志API、静态日志缓存以及分布式日志收集等核心技能。
场景一:基础日志级别配置
基础日志记录是ASP.NET Core应用开发的必备技能。在practical-aspnetcore项目的logging-1示例中,展示了如何配置不同日志级别并输出日志信息。
ASP.NET Core定义了6个日志级别,按严重程度从低到高依次为:
- Trace (0):最详细的调试信息
- Debug (1):开发环境调试信息
- Information (2):运行时正常信息
- Warning (3):不影响运行的异常情况
- Error (4):功能异常但不终止应用
- Critical (5):严重错误可能导致应用终止
以下代码演示了如何设置全局最小日志级别并输出不同级别的日志:
var builder = WebApplication.CreateBuilder();
builder.Logging.SetMinimumLevel(LogLevel.Warning);
builder.Logging.AddConsole();
var app = builder.Build();
app.Run(context =>
{
var log = app.Logger;
log.LogTrace("Trace message"); // 不会显示,级别低于Warning
log.LogDebug("Debug message"); // 不会显示,级别低于Warning
log.LogInformation("Information message"); // 不会显示,级别低于Warning
log.LogWarning("Warning message"); // 显示
log.LogError("Error message"); // 显示
log.LogCritical("Critical message"); // 显示
return context.Response.WriteAsync("Hello world.");
});
app.Run();
通过调整SetMinimumLevel参数,可以控制应用输出的日志详细程度。在开发环境通常使用较低级别(如Debug),生产环境则使用较高级别(如Warning)以减少性能开销。
场景二:日志过滤规则设置
当日志量过大时,我们需要对日志进行过滤,只保留关键信息。logging-2示例展示了如何基于日志类别设置不同的过滤规则。
日志过滤可以通过代码或配置文件实现。以下代码演示了如何对不同命名空间的日志设置不同级别:
var builder = WebApplication.CreateBuilder();
// 对Microsoft命名空间的日志只显示Warning及以上级别
builder.Logging.AddFilter("Microsoft", LogLevel.Warning);
// 对AppLogger命名空间的日志显示所有级别
builder.Logging.AddFilter("AppLogger", LogLevel.Trace);
builder.Logging.AddConsole();
var app = builder.Build();
// ...
除了代码方式,还可以通过配置文件进行过滤设置。在appSettings.json中添加日志配置:
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Error",
"AppLogger": "Information"
}
}
}
日志过滤功能可以帮助我们:
- 减少第三方库的日志干扰
- 针对不同模块设置不同详细程度
- 在生产环境隐藏敏感信息
- 提高日志系统性能
场景三:JSON结构化日志输出
在日志分析和处理时,结构化日志比纯文本日志更具优势。logging-3示例展示了如何配置JSON格式的控制台日志输出。
通过添加JSON控制台日志提供器,可以将日志输出为结构化的JSON格式,便于日志聚合工具(如ELK、Splunk)进行解析和分析:
using System.Text.Json;
var builder = WebApplication.CreateBuilder();
builder.Logging.AddFilter("Microsoft", LogLevel.Warning);
builder.Logging.AddFilter("AppLogger", LogLevel.Trace);
builder.Logging.AddJsonConsole(options =>
{
options.JsonWriterOptions = new JsonWriterOptions { Indented = true };
});
var app = builder.Build();
// ...
配置后,控制台将输出如下格式的JSON日志:
{
"EventId": 0,
"LogLevel": "Information",
"Category": "Program",
"Message": "This is a information message",
"State": {
"Message": "This is a information message"
}
}
JSON结构化日志的优势在于:
- 包含丰富的元数据(日志级别、类别、事件ID等)
- 便于机器解析和自动化处理
- 支持自定义字段扩展
- 可配置的输出格式
场景四:高性能日志API生成
对于高性能要求的应用,使用LoggerMessageAttribute可以显著提升日志性能。logging-4示例展示了如何通过源代码生成创建高性能日志API。
传统的LogInformation等方法会带来一定的性能开销,而使用LoggerMessageAttribute可以在编译时生成高效的日志方法,避免运行时字符串格式化开销:
public static partial class EvenOddLogs
{
[LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "input number is even!: {number}")]
public static partial void LogInformationWhenInputNumberIsEven(this ILogger logger, long number);
[LoggerMessage(EventId = 2, Level = LogLevel.Information, Message = "input number is odd!: {number}")]
public static partial void LogInformationWhenInputNumberIsOdd(this ILogger logger, long number);
}
使用生成的日志方法:
app.MapGet("/log-it", ([FromQuery] int number) =>
{
var log = app.Logger;
if (number % 2 == 0)
log.LogInformationWhenInputNumberIsEven(number);
else
log.LogInformationWhenInputNumberIsOdd(number);
return Results.Content("Check terminal for logs.");
});
高性能日志API的优势:
- 编译时检查日志参数类型
- 减少内存分配和GC压力
- 支持结构化日志属性
- 提高应用吞吐量,尤其在高频日志场景
场景五:静态日志缓存实现
在大型应用中,频繁创建日志器(ILogger)会带来性能开销。logging-5示例展示了如何实现静态日志缓存,优化日志器的创建和使用。
通过创建静态日志工厂类,可以缓存日志器实例,避免重复创建:
public static class Log
{
static ILoggerFactory _loggerFactory;
static readonly ConcurrentDictionary<string, ILogger> _loggers = new();
public static void Configure(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
public static ILogger CreateLogger<T>() =>
_loggers.GetOrAdd(typeof(T).FullName, _ => _loggerFactory.CreateLogger<T>());
public static ILogger CreateLogger(string categoryName) =>
_loggers.GetOrAdd(categoryName, _ => _loggerFactory.CreateLogger(categoryName));
}
在应用启动时配置日志工厂:
var app = builder.Build();
Log.Configure(app.Services.GetRequiredService<ILoggerFactory>());
使用静态日志器:
app.Run(context =>
{
var log = Log.CreateLogger("main");
log.LogWarning("Warning message");
// ...
return context.Response.WriteAsync("Hello world.");
});
静态日志缓存的优势:
- 减少内存分配和对象创建开销
- 简化日志器的获取方式
- 统一日志配置和管理
- 提高应用性能,尤其在高频日志场景
场景六:Grafana Loki分布式日志收集
对于分布式应用,集中式日志收集至关重要。logging-Loki示例展示了如何将ASP.NET Core日志发送到Grafana Loki进行集中管理和分析。
Loki是Grafana Labs开发的水平可扩展、高可用性的日志聚合系统,专为容器和微服务环境设计。以下代码演示了如何配置Loki日志提供器:
using LokiLoggingProvider.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddLoki(configure =>
{
configure.Client = PushClient.Grpc;
configure.StaticLabels.JobName = "LokiWebApplication";
});
var app = builder.Build();
app.MapGet("/test", (ILoggerFactory loggerFactory) =>
{
var logger = loggerFactory.CreateLogger("Start");
logger.LogTrace("Trace message");
logger.LogDebug("Debug message");
logger.LogInformation("Information message");
logger.LogWarning("Warning message");
logger.LogError("Error message");
logger.LogCritical("Critical message");
return "OK";
});
app.Run();
为了简化Loki的部署和配置,示例中提供了docker-compose.yml文件,可以一键启动Loki和Grafana服务:
version: "3"
services:
loki:
image: grafana/loki:latest
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- ./grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=secret
使用Loki进行分布式日志收集的优势:
- 集中管理多个服务实例的日志
- 支持日志标签和高效查询
- 与Grafana无缝集成,提供可视化分析
- 适合云原生和微服务架构
总结与最佳实践
通过practical-aspnetcore项目的6个日志场景实践,我们系统学习了ASP.NET Core日志系统的核心功能和高级用法。以下是一些最佳实践建议:
- 环境差异化配置:开发环境使用详细日志级别,生产环境使用高级别日志
- 合理使用日志级别:根据信息重要性选择适当的日志级别
- 结构化日志优先:尽量使用结构化日志,便于后续分析和处理
- 性能优化:对高频日志场景使用
LoggerMessageAttribute和静态日志缓存 - 集中式收集:在分布式系统中使用Loki等工具进行日志集中管理
- 敏感信息保护:避免在日志中记录密码、令牌等敏感信息
更多日志相关示例和详细代码,请参考practical-aspnetcore项目的logging目录。掌握日志系统不仅能帮助我们更好地调试应用,还能为系统监控、性能优化和问题排查提供关键支持。
希望本文对你理解和使用ASP.NET Core日志系统有所帮助。如果有任何问题或建议,欢迎在项目仓库中提交issue或PR。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



