如何在 aspnetcore 中降低 mvc 管道的日志级别?

8
在ASPNETCORE 2.0项目中,我向日志工厂添加了一个日志提供程序(serilog),以及一个控制台接收器。它很好用,但我注意到所有的框架请求管道(比如http请求响应)都将每个细节都作为INFO记录下来。
[17:37:26 INF] Request starting HTTP/1.1 GET http://localhost:5000/test/health
[17:37:26 INF] Executing action method DAS.Gateways.Command.Api.Controllers.TestController.HealthCheck (DAS.Gateways.Command.Api) with arguments (null) - ModelState is Valid
[17:37:26 INF] Health check called.
[17:37:27 INF] Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext.
[17:37:27 INF] Executed action DAS.Gateways.Command.Api.Controllers.TestController.HealthCheck (DAS.Gateways.Command.Api) in 203.8825ms
[17:37:27 INF] Request finished in 343.9801ms 200 application/json; charset=utf-8
[17:38:07 INF] Request starting HTTP/1.1 GET http://localhost:5000/test/health
[17:38:07 INF] Executing action method DAS.Gateways.Command.Api.Controllers.TestController.HealthCheck (DAS.Gateways.Command.Api) with arguments (null) - ModelState is Valid
[17:38:07 INF] Health check called.
[17:38:07 INF] Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext.
[17:38:07 INF] Executed action DAS.Gateways.Command.Api.Controllers.TestController.HealthCheck (DAS.Gateways.Command.Api) in 53.5876ms
[17:38:07 INF] Request finished in 60.2195ms 200 application/json; charset=utf-8

Info是我们在生产日志记录中使用的最低日志级别,我们有一个Loggly接收器,每天限制1GB,因此我觉得将MVC日志记录的所有请求信息都标记为INFO有点过分了,我想将其降低到DEBUG。明确一点,我不想提高我的日志记录级别以防止INFO达到接收器,我希望.Net将其日志记录级别从INFO降低到DEBUG。

这种可能吗?如何实现?

3个回答

10

您需要使用日志过滤

您可以为特定提供程序和类别或所有提供程序或所有类别指定最低日志级别。任何低于最低级别的日志都不会传递给该提供程序,因此它们不会被显示或存储。

过滤规则可以通过配置或代码定义。以下是代码示例:

    // using Serilog.Extensions.Logging;

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureLogging(logging => 
            {
                logging.AddFilter<SerilogLoggerProvider>("Microsoft", LogLevel.Warning);
            }
            .UseStartup<Startup>()
            .Build();

请注意,这种情况下的AddFilter仅适用于Serilog日志提供程序,因为我们指定了提供程序类型。如果您想为所有提供程序定义过滤器,请使用:logging.AddFilter("Microsoft", LogLevel.Warning);

1
那这不是意味着我将看不到这些日志吗?这不是我想要的。我想改变日志本身的级别,而不是将其传输到汇聚器的级别。我猜这至少解决了过度记录的问题。所以无论如何,我给一个赞。 - Sinaesthetic

1
一个可能的解决方案是创建自己的ILoggerProviderILogger实现,作为底层提供程序的桥接,然后使您的ILogger.Log()方法根据记录器的类别名称做出实际的记录决策,然后修改日志级别。
在我的情况下,我假设所有ASP.NET Core应用程序都具有以"Microsoft.AspNetCore"开头的记录器类别名称,然后将这些事件的日志级别从信息更改为调试,类似于:
public class MyLogger : ILogger
{
    private string  categoryName;
    private ILogger baseLogger;

    public MyLogger(string categoryName, ILogger baseLogger)
    {
        this.categoryName = categoryName;
        this.baseLogger   = baseLogger;
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (logLevel == LogLevel.Information 
           && categoryName.StartsWith("Microsoft.AspNetCore"))
        {
            logLevel = LogLevel.Debug;
        }

        baseLogger.Log(logLevel, eventId, state, exception, formatter);
    }
}

这是一个小技巧,但它有效地将被记录为“INFORMATION”的ASP.NET事件转换为“DEBUG”事件,因此当您不需要它们时,它们不会填满您的日志,但您仍然可以将日志级别设置为DEBUG以显示它们。
更新:
下面的Startup.cs文件演示了如何连接它:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Logging.Debug;

namespace WebApplication1
{
    public class LoggerProviderShim : ILoggerProvider
    {
        private ILoggerProvider baseLoggerProvider;

        public LoggerProviderShim(ILoggerProvider baseLoggerProvider)
        {
            this.baseLoggerProvider = baseLoggerProvider;
        }

        public ILogger CreateLogger(string categoryName)
        {
            return new LoggerShim(baseLoggerProvider.CreateLogger(categoryName), categoryName);
        }

        public void Dispose()
        {
            baseLoggerProvider.Dispose();
        }
    }

    public class LoggerShim : ILogger
    {
        private ILogger     baseLogger;
        private bool        treatInfoAsDebug;

        public LoggerShim(ILogger baseLogger, string categoryName)
        {
            this.baseLogger       = baseLogger;
            this.treatInfoAsDebug = categoryName != null && categoryName.StartsWith("Microsoft.AspNetCore.");
        }

        public IDisposable BeginScope<TState>(TState state)
        {
            return baseLogger.BeginScope(state);
        }

        public bool IsEnabled(LogLevel logLevel)
        {
            return baseLogger.IsEnabled(logLevel);
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            if (treatInfoAsDebug && logLevel == LogLevel.Information)
            {
                logLevel = LogLevel.Debug;
            }

            baseLogger.Log(logLevel, eventId, state, exception, formatter);
        }
    }

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            var debugLogProvider = new DebugLoggerProvider();

            loggerFactory.AddProvider(debugLogProvider);
            //loggerFactory.AddProvider(new LoggerProviderShim(debugLogProvider));

            app.UseMvc();
        }
    }
}

我在文件顶部添加了LoggerProviderShimLoggerShim类。 LoggerProviderShim旨在包装特定的日志记录器提供程序实现。 对于此示例,我正在包装一个DebugLoggerProviderLoggerShim用于包装由包装(真实)日志记录器提供程序返回的日志记录器。
这里的想法是,您不会在Startup.Configure()中向日志记录器工厂添加真正的ILoggerProvider,而是将真正的提供程序包装在LoggerProviderShim中,然后将该封套添加到日志记录器工厂中。 LoggerProviderShim通过获取来自真实日志记录器提供程序的真实ILogger,然后将其包装在LoggerShim中,然后返回该封套。 LoggerShim构造函数检查创建的日志记录器类别名称,以决定是否将INFORMATION事件记录为DEBUG。 在这种情况下,我们正在寻找来自ASP.NET CORE组件的日志记录器类别名称,方法是查找来自ASP的类别名称(例如,由“Microsoft.AspNetCore。”前缀)。

在调用底层真实的记录器之前,记录器shim的Log()方法会将这些记录器的信息日志级别更改为DEBUG。

您可以通过在简单的WebAPI项目中包含此代码来查看其效果:

  1. 确保appsettings.json中的日志级别设置为Debug
  2. 运行应用程序并多次访问控制器端点。
  3. 在Visual Studio DEBUG输出面板中,注意ASP.NET事件被记录为INFORMATION
  4. 停止应用程序,在Startup.Configure()方法中注释掉第一个AddProvider()调用并取消注释第二个调用,然后再次测试应用程序。
  5. 现在请注意,ASP.NET事件被记录为DEBUG。Shim转换了事件级别。

您需要特别包装任何您关心的记录提供程序。在此示例中,我包装了DebugLogProvider。您需要分别针对Application Insights或任何其他记录提供程序执行相同的操作(我是否已经提到过这是一种有点hack的方法:)


这是哪个ILogger?Microsoft.Extensions.Logging.ILogger吗?看一下你是如何插入它的会有所帮助。我对新的日志框架还不太熟悉。 - Sinaesthetic

0

所有关于HTTP请求和响应的信息级别日志都可以通过设置“Microsoft”的LoggerConfiguration中的“MinimumLevel”来关闭,因为这些日志来自“Microsoft.AspNetCore”。以下是在代码中完成此操作的方法:

Log.Logger = new LoggerConfiguration()
            .ReadFrom.Configuration(Configuration)
            .MinimumLevel.Override("Microsoft",LogEventLevel.Warning)
            .CreateLogger();

这也可以通过以下方式在 appsettings.json 文件中进行配置

"Serilog": {
"MinimumLevel": {
  "Default": "Debug",
  "Override": {
    "Microsoft": "Warning"
  }
},
"WriteTo": [
  {
    "Name": "Async",
    "Args": {
      "configure": [
        {
          "Name": "Console",
          "Args": {
            "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
          }
        },
        {
          "Name": "File",
          "Args": {
            "path": "Logs/log.txt",
            "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
            //"fileSizeLimitBytes": "1073741824",
            //"buffered": false,
            //"shared": false,
            "rollingInterval": "Minute"
            //"rollOnFileSizeLimit": false,
            //"retainedFileCountLimit": 31
          }
        }
      ]
    }
  }
]

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接