.NET 7 API中基于来源区分Graylog日志配置的正确实现方式
.NET 7 API中针对WebApp上报日志配置独立Graylog日志源的正确实现
问题背景
基于.NET 7 API开发的React应用,使用Graylog做日志记录。需求是提供/logs API端点接收Web应用上报的错误日志,且Web应用上报的日志需使用独立的LogSource(标记为WebApp),API自身日志使用另一LogSource(标记为API)。
当前问题:每次命中/logs端点时会生成两条内容相同但LogSource分别为API和WebApp的日志记录,原因是每次请求都会向LoggerFactory添加新的GELF日志提供器,导致全局存在多个日志记录器,所有日志被重复输出。
当前代码的核心问题
LoggerFactory是全局共享组件,禁止在请求处理过程中动态添加日志提供器,每次调用AddGelf都会新增日志记录器实例,后续所有日志会被所有已添加的记录器处理。- 现有中间件逻辑会在每次
/logs请求时重复添加WebApp的GELF配置,导致日志提供器数量不断累积,最终所有日志被多份记录。
正确实现方案
方案一:使用命名日志记录器(推荐)
在应用启动时预先配置两个独立的GELF日志提供器,分别对应API和WebApp的日志源,再在不同场景下使用对应的命名日志记录器。
- 修改appsettings.json配置
明确区分两个日志源的配置:
"Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" }, "GELF:API": { "Host": "xxx.graylog.com", "LogSource": "API" }, "GELF:WebApp": { "Host": "xxx.graylog.com", "LogSource": "WebApp" } }
- 在Program.cs中预先配置所有GELF日志提供器
在应用启动阶段完成日志配置,避免请求时动态修改:
var builder = WebApplication.CreateBuilder(args); // 配置API的GELF日志提供器 builder.Logging.AddGelf(options => { builder.Configuration.GetSection("Logging:GELF:API").Bind(options); options.AdditionalFields["machine_name"] = Environment.MachineName; }); // 配置WebApp的GELF日志提供器 builder.Logging.AddGelf(options => { builder.Configuration.GetSection("Logging:GELF:WebApp").Bind(options); options.AdditionalFields["machine_name"] = Environment.MachineName; }); // 其他服务配置... var app = builder.Build(); // 移除原有动态添加日志配置的LoggingMiddleware,无需再使用 // app.UseMiddleware<LoggingMiddleware>(); // 异常处理器配置 using (var serviceScope = app.Services.CreateScope()) { var services = serviceScope.ServiceProvider; var logger = services.GetRequiredService<MyProject1.Logging.IMyLogger<MyProject1.Api.Extensions.Project1Exception>>(); app.ConfigureExceptionHandler(logger); } app.Run();
- 在LogsController中使用WebApp专属日志记录器
在处理WebApp上报日志的控制器中,创建并使用WebApp命名的日志记录器:
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace MyProject1.Api.Controllers { [ApiController] [Route("logs")] public class LogsController : ControllerBase { private readonly ILogger _webAppLogger; public LogsController(ILoggerFactory loggerFactory) { // 创建对应WebApp日志源的命名日志记录器 _webAppLogger = loggerFactory.CreateLogger("WebApp"); } [HttpPost] public IActionResult SubmitWebAppLog([FromBody] WebAppLogModel logData) { // 使用WebApp专属日志记录器输出日志,只会触发WebApp的GELF配置 _webAppLogger.LogError(logData.ErrorMessage, logData.StackTrace); return Ok(); } } public class WebAppLogModel { public string ErrorMessage { get; set; } public string StackTrace { get; set; } } }
- API自身日志保持原有使用方式
API其他控制器或类中,继续使用依赖注入的ILogger<T>即可,默认会使用API的GELF日志源:
public class SomeApiController : ControllerBase { private readonly ILogger<SomeApiController> _logger; public SomeApiController(ILogger<SomeApiController> logger) { _logger = logger; } [HttpGet] public IActionResult Get() { // 此日志会使用API的LogSource _logger.LogInformation("API处理了一个请求"); return Ok(); } }
方案二:使用日志过滤器路由(复杂场景可选)
如果需要更灵活的动态日志路由逻辑,可以通过自定义日志过滤器,根据日志的自定义属性选择对应的日志提供器。此方案复杂度较高,适合需动态判断的场景,大多数情况下方案一足够满足需求。
效果验证
- WebApp通过
/logs端点上报的日志,只会在Graylog中出现一条LogSource=WebApp的记录。 - API自身产生的日志,只会在Graylog中出现一条
LogSource=API的记录。 - 不会再出现重复日志的问题,日志提供器数量固定,不会随请求累积。
内容的提问来源于stack exchange,提问作者Junaid
相关产品推荐
相关产品推荐

