2.5 日志 (Logging) 2.5 日志 (Logging) in ASP.NET Core 在 ASP.NET Core 应用中,日志记录是一个至关重要的方面,它帮助开发者诊断问题、监控应用性能以及审计操作。ASP.NET Core 提供了一个灵活且可扩展的日志记录框架,允许你将日志消息发送到各种不同的目标,例如控制台、文件、数据库或云服务。 2.5.1 日志框架概述 ASP.NET Core 日志框架基于 接口。你可以通过依赖注入将 注入到你的类中,其中 通常是你的类的类型。 核心组件: ILogger: 定义了日志记录方法,例如 、 、 等。 ILoggerFactory: 用于创建 实例。ASP.NET Core 依赖注入容器默认提供 。
在 ASP.NET Core 应用中,日志记录是一个至关重要的方面,它帮助开发者诊断问题、监控应用性能以及审计操作。ASP.NET Core 提供了一个灵活且可扩展的日志记录框架,允许你将日志消息发送到各种不同的目标,例如控制台、文件、数据库或云服务。
ASP.NET Core 日志框架基于 ILogger 接口。你可以通过依赖注入将 ILogger<T> 注入到你的类中,其中 T 通常是你的类的类型。
核心组件:
ILogger: 定义了日志记录方法,例如 LogInformation、LogError、LogWarning 等。
ILoggerFactory: 用于创建 ILogger 实例。ASP.NET Core 依赖注入容器默认提供 ILoggerFactory。
Logger Providers: 将日志消息写入到特定目标(例如控制台、文件)的组件。ASP.NET Core 默认提供了一些内置的 provider,例如 ConsoleLoggerProvider 和 DebugLoggerProvider。你也可以创建自定义的 provider。
Log Levels: 定义了日志消息的严重程度,例如 Trace、Debug、Information、Warning、Error、Critical。你可以配置应用程序记录的最低日志级别。
Log Filters: 允许你根据日志级别、类别或事件 ID 过滤日志消息。
流程图:
ASP.NET Core 应用程序模板默认配置了基本的日志记录功能。你可以在 Program.cs 文件中配置日志记录:
using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; 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>(); }) .ConfigureLogging(logging => { // 清除默认的日志提供程序 logging.ClearProviders(); // 添加控制台日志提供程序 logging.AddConsole(); // 可选: 添加调试日志提供程序 logging.AddDebug(); // 可选: 配置最低日志级别 logging.SetMinimumLevel(LogLevel.Information); }); }
代码解释:
Host.CreateDefaultBuilder(args) 创建默认的 IHostBuilder,它已经配置了一些基本的服务,包括日志记录。
ConfigureLogging 方法允许你配置日志记录。
logging.ClearProviders() 清除默认的日志提供程序,以便你可以添加你自己的。
logging.AddConsole() 添加控制台日志提供程序,将日志消息写入到控制台。
logging.AddDebug() 添加调试日志提供程序,将日志消息写入到调试输出。
logging.SetMinimumLevel(LogLevel.Information) 设置最低日志级别为 Information。这意味着只有级别为 Information、Warning、Error 和 Critical 的日志消息才会被记录。
在 Controller 中使用日志:
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace MyAspNetCoreApp.Controllers { [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] public IActionResult Get() { _logger.LogInformation("Get method called"); try { // 一些可能抛出异常的代码 throw new System.Exception("模拟异常"); } catch (System.Exception ex) { _logger.LogError(ex, "An error occurred in Get method."); return StatusCode(500, "Internal Server Error"); } return Ok(new string[] { "value1", "value2" }); } } }
代码解释:
ILogger<WeatherForecastController> 通过构造函数注入到 WeatherForecastController 中。
_logger.LogInformation("Get method called") 记录一条信息级别的日志消息。
_logger.LogError(ex, "An error occurred in Get method.") 记录一条错误级别的日志消息,并包含异常信息。 LogError 方法的第一个参数是异常对象,第二个参数是消息字符串。
你可以在 appsettings.json 文件中配置日志级别。
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
代码解释:
Logging.LogLevel.Default 设置默认的日志级别为 Information。
Logging.LogLevel.Microsoft 设置 Microsoft 命名空间下的日志级别为 Warning。 这意味着来自 Microsoft 命名空间的日志消息,只有级别为 Warning、Error 和 Critical 的才会被记录。
Logging.LogLevel.Microsoft.Hosting.Lifetime 设置 Microsoft.Hosting.Lifetime 命名空间下的日志级别为 Information。 这个命名空间通常用于记录应用程序启动和关闭事件。
你也可以在代码中动态更改日志级别:
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Configuration; public class MyService { private readonly ILogger<MyService> _logger; private readonly IConfiguration _configuration; public MyService(ILogger<MyService> logger, IConfiguration configuration) { _logger = logger; _configuration = configuration; } public void DoSomething() { var logLevelString = _configuration["LogLevel:MyService"]; if (Enum.TryParse<LogLevel>(logLevelString, out var logLevel)) { if (_logger.IsEnabled(logLevel)) { _logger.Log(logLevel, "Doing something..."); } } else { _logger.LogWarning("Invalid LogLevel configuration for MyService."); } } }
在这个例子中,日志级别是从 appsettings.json (或任何其他配置源) 中读取的,允许你根据需要动态调整日志记录行为。
日志过滤允许你根据日志级别、类别或事件 ID 来控制哪些日志消息被记录。 你可以在 appsettings.json 文件中配置日志过滤器:
{ "Logging": { "LogLevel": { "Default": "Information", "MyAspNetCoreApp.Controllers.WeatherForecastController": "Debug" }, "Console": { "LogLevel": { "Default": "Information", "MyAspNetCoreApp.Controllers.WeatherForecastController": "Debug" } } }, "AllowedHosts": "*" }
代码解释:
Logging.LogLevel.Default 设置默认的日志级别为 Information。
Logging.LogLevel.MyAspNetCoreApp.Controllers.WeatherForecastController 设置 MyAspNetCoreApp.Controllers.WeatherForecastController 类别下的日志级别为 Debug。 这意味着只有来自该 controller 的日志消息,级别为 Debug、Information、Warning、Error 和 Critical 的才会被记录。
Logging.Console.LogLevel 进一步配置了控制台日志提供程序的日志级别。
结构化日志允许你将日志消息作为结构化数据(例如 JSON)记录,而不是简单的文本字符串。 这使得更容易查询和分析日志数据。
为了使用结构化日志,你需要使用支持结构化日志的日志提供程序,例如 Serilog 或 NLog。
使用 Serilog:
安装 Serilog NuGet 包:
Install-Package Serilog.AspNetCore Install-Package Serilog.Sinks.Console # or any other sink you want to use
配置 Serilog:
using Serilog; public class Program { public static void Main(string[] args) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .Enrich.FromLogContext() .WriteTo.Console() // 输出到控制台 .WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Day) // 输出到文件,每天生成一个新文件 .CreateLogger(); try { Log.Information("Starting web host"); CreateHostBuilder(args).Build().Run(); } catch (Exception ex) { Log.Fatal(ex, "Host terminated unexpectedly"); } finally { Log.CloseAndFlush(); } } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseSerilog() // 使用 Serilog .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
在 Controller 中使用 Serilog:
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Serilog.Context; namespace MyAspNetCoreApp.Controllers { [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] public IActionResult Get() { using (LogContext.PushProperty("Endpoint", "/WeatherForecast")) { _logger.LogInformation("Get method called with parameters {Param1} and {Param2}", "value1", "value2"); // 结构化日志 try { // 一些可能抛出异常的代码 throw new System.Exception("模拟异常"); } catch (System.Exception ex) { _logger.LogError(ex, "An error occurred in Get method."); return StatusCode(500, "Internal Server Error"); } return Ok(new string[] { "value1", "value2" }); } } } }
代码解释:
Log.Logger = new LoggerConfiguration()...CreateLogger() 配置 Serilog 日志记录器。
Enrich.FromLogContext() 允许你从 LogContext 中添加属性到日志消息中。
WriteTo.Console() 将日志消息写入到控制台。
WriteTo.File() 将日志消息写入到文件。
UseSerilog() 将 Serilog 集成到 ASP.NET Core 应用程序中。
LogContext.PushProperty("Endpoint", "/WeatherForecast") 将 Endpoint 属性添加到日志上下文,以便将其包含在所有后续的日志消息中。
_logger.LogInformation("Get method called with parameters {Param1} and {Param2}", "value1", "value2") 记录一条结构化日志消息,其中包含参数 Param1 和 Param2 的值。
你可以创建自定义的日志提供程序,以便将日志消息写入到特定的目标。
创建一个简单的自定义日志提供程序:
using Microsoft.Extensions.Logging; public class CustomLoggerProvider : ILoggerProvider { private readonly string _filePath; public CustomLoggerProvider(string filePath) { _filePath = filePath; } public ILogger CreateLogger(string categoryName) { return new CustomLogger(categoryName, _filePath); } public void Dispose() { // 释放资源 } } public class CustomLogger : ILogger { private readonly string _categoryName; private readonly string _filePath; public CustomLogger(string categoryName, string filePath) { _categoryName = categoryName; _filePath = filePath; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { if (!IsEnabled(logLevel)) { return; } var message = formatter(state, exception); string logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{logLevel}] {_categoryName}: {message}{Environment.NewLine}"; File.AppendAllText(_filePath, logEntry); } public bool IsEnabled(LogLevel logLevel) { // 自定义逻辑来确定是否启用给定的日志级别 return logLevel >= LogLevel.Information; // 示例:只记录 Information 及以上级别的日志 } public IDisposable BeginScope<TState>(TState state) { // 可选:实现作用域逻辑 return null; } }
在 Program.cs 中注册自定义日志提供程序:
using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; 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>(); }) .ConfigureLogging(logging => { logging.ClearProviders(); logging.AddProvider(new CustomLoggerProvider("logs/custom.txt")); // 添加自定义日志提供程序 }); }
代码解释:
CustomLoggerProvider 实现了 ILoggerProvider 接口,并负责创建 CustomLogger 实例。
CustomLogger 实现了 ILogger 接口,并将日志消息写入到指定的文件中。
logging.AddProvider(new CustomLoggerProvider("logs/custom.txt")) 将自定义日志提供程序添加到 ASP.NET Core 应用程序中。
使用有意义的日志消息: 日志消息应该清晰、简洁,并提供足够的信息来诊断问题。
使用正确的日志级别: 根据日志消息的严重程度选择合适的日志级别。
避免记录敏感信息: 不要在日志消息中记录密码、信用卡号或其他敏感信息。
使用结构化日志: 使用结构化日志可以更容易地查询和分析日志数据。
定期审查日志: 定期审查日志可以帮助你发现潜在的问题并改进应用程序的性能。
集中式日志管理: 考虑使用集中式日志管理系统(例如 Elasticsearch、Splunk 或 Azure Monitor)来收集、存储和分析日志数据。
通过遵循这些最佳实践,你可以有效地利用 ASP.NET Core 的日志记录框架来构建更健壮、更易于维护的应用程序。