如何关闭 ASP.NET 核心框架的日志记录

如何关闭 ASP.NET 对每个请求所做的日志记录,例如。

INFO 09:38:41用户配置文件可用。使用“ C: Users xxxx xxxx AppData Local ASP.NET DataProtection-Keys”作为密钥存储库,使用 Windows DPAPI 对静止的密钥进行加密。
调试09:38:41主机开始
调试09:38:41主机开始
请求启动 HTTP/1.1 GET < a href = “ HTTP://localhost: 23369/”rel = “ norefrer”> HTTP://localhost:23369/
INFO 09:38:41请求启动 HTTP/1.1 DEBUG http://localhost:23369/ text/html 不支持调试09:38:41调试请求
DEBUG 09:38:41请求路径/与支持的文件类型不匹配
DEBUG 09:38:41 Request 成功地匹配了名称为‘ default’和模板为‘{ controller = Home }/{ action = Index }/{ id? }’的路由。 DEBUG 09:38:41 Request 成功地匹配了名称为‘ default’和模板为‘{ controller = Home }/{ action = Index }/{ id? }’的路由。 调试09:38:41执行动作论坛。控制器。家庭控制器。索引
调试09:38:41执行动作论坛。控制器。家庭控制器。索引
INFO 09:38:41正在执行动作方法 Forums. Controllers. HomeController. 带参数的索引()-ModelState 是有效的’
执行动作方法论坛。控制器。家控制器。索引
..

我还不知道怎么关掉这个登录。

这是我在 Startup类中的 Configure方法:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddProvider(new Log4NetProvider());


if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");


// For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
try
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
serviceScope.ServiceProvider.GetService<ApplicationDbContext>()
.Database.Migrate();
}
}
catch { }
}


app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());


app.UseStaticFiles();


app.UseIdentity();


// To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715


app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}

这是我的 project.json 文件:

"dependencies": {
"EntityFramework.Commands": "7.0.0-rc1-final",
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",
"log4net": "2.0.5",
"Microsoft.AspNet.Authentication.Cookies": "1.0.0-rc1-final",
"Microsoft.AspNet.Diagnostics.Entity": "7.0.0-rc1-final",
"Microsoft.AspNet.Identity.EntityFramework": "3.0.0-rc1-final",
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
"Microsoft.AspNet.Tooling.Razor": "1.0.0-rc1-final",
"Microsoft.Extensions.CodeGenerators.Mvc": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0-rc1-final",
"Microsoft.Extensions.Logging": "1.0.0-rc1-final",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc1-final"
},


"commands": {
"web": "Microsoft.AspNet.Server.Kestrel",
"ef": "EntityFramework.Commands"
},


"frameworks": {
"dnx451": { }
},

更新:
我的 log4net 提供者从这里获取了一个 href = “ http://dotnetLiberty.com/index.php/2015/11/09/asp-net-5-logging-with-log4net/”rel = “ noReferrer”>

124035 次浏览

In and before ASP.NET 5 RC1 (now ASP.NET Core 1.0), you could do it via the logger factory, i.e.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// completely disable logging or use one of the other levels, such as Error, Critical, Warning etc.
loggerFactory.MinimumLevel = LogLevel.None;
}

However, with the current branch (not released yet, but available via nightly builds), this has been removed. Now you need to pass the LogLevel per provider. Typically this is done via extension method.

For the built in console logger, it would be loggerFactory.AddConsole(minimumLevel: LogLevel.Warning); for example.

Since your logger provider is a custom one, you will have to configure it yourself. Take a look on how the console logger does it. It passes a delegate to the provider, that does the filtering.

From GitHub Source:

public static ILoggerFactory AddConsole(
this ILoggerFactory factory,
LogLevel minLevel,
bool includeScopes)
{
factory.AddConsole((category, logLevel) => logLevel >= minLevel, includeScopes);
return factory;
}

Of course instead of passing a delegate you can also directly set the log level of log4net.

Update: To extend on what I've pointed out in the comments

The ILoggerProvider is only a wrapper around the actual logging framework. In the simple case of ConsoleLoggerProvider, there is no framework as all behind it, just a simple Console.WriteLine call.

In case of log4net, it's obvious from the example that logging can be enabled on a per level basis. This isn't possible with the .NET Core logger abstraction liked above, as the abstraction doesn't do any filtering.

In a log4net ILoggerProvider one would simply route all log levels to the log4net net library and have it filter it.

Based on the linked GitHub issue @haim770 created, you have the SourceContext for filtering and if log4net doesn't have a concept of SourceContext, you'll have to implement this in the provider. If it has a concept of SourceContext, then the provider needs to reroute/translate it into the structure log4net expects it.

As you can see, the logger itself always stays unaware about internal specifics and implementation details of ASP.NET. The Log4NetProvider can't and shouldn't, because it's task is to translate/wrap around that api. Providers are just abstractions, so we don't have to leak implementation details into a library for example.

Since the new logging infrastructure is being used (by design) by asp.net itself (as well as other vendor code), it's up to the ILoggerProvider implementation to decide whether it wants to log that source or not.

Here's a revised implementation for log4net that adds a basic source filtering:

public class Log4NetProvider : ILoggerProvider
{
private static readonly NoopLogger _noopLogger = new NoopLogger();
private readonly Func<string, bool> _sourceFilterFunc;
private readonly ConcurrentDictionary<string, Log4NetLogger> _loggers = new ConcurrentDictionary<string, Log4NetLogger>();


public Log4NetProvider(Func<string, bool> sourceFilterFunc = null)
{
_sourceFilterFunc = sourceFilterFunc != null ? sourceFilterFunc : x => true;
}


public ILogger CreateLogger(string name)
{
if (!_sourceFilterFunc(name))
return _noopLogger;


return _loggers.GetOrAdd(name, x => new Log4NetLogger(name));
}


public void Dispose()
{
_loggers.Clear();
}


private class NoopLogger : ILogger
{
public IDisposable BeginScopeImpl(object state)
{
return null;
}


public bool IsEnabled(LogLevel logLevel)
{
return false;
}


public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
}
}
}

And the Log4NetAspExtensions:

public static void ConfigureLog4Net(this IApplicationEnvironment appEnv, string configFileRelativePath)
{
GlobalContext.Properties["appRoot"] = appEnv.ApplicationBasePath;
XmlConfigurator.Configure(new FileInfo(Path.Combine(appEnv.ApplicationBasePath, configFileRelativePath)));
}


public static void AddLog4Net(this ILoggerFactory loggerFactory, Func<string, bool> sourceFilterFunc = null)
{
loggerFactory.AddProvider(new Log4NetProvider(sourceFilterFunc));
}


public static void AddLog4Net(this ILoggerFactory loggerFactory)
{
loggerFactory.AddLog4Net(null);
}

Possible usage (in Startup.cs):

public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv, ILoggerFactory loggerFactory)
{
appEnv.ConfigureLog4Net("log4net.xml");


loggerFactory.AddLog4Net(x => !x.StartsWith("Microsoft."));
}

I'm not sure if I am missing something but don't you just want to raise the log level for the Microsoft logs?

Edit appsettings.json (assumes .AddJsonFile("appsettings.json", ...))

{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "Information"

To

{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "None"

Or the same modification via environment variables (assumes .AddEnvironmentVariables())

Logging:LogLevel:Microsoft=None

You can also be more specific, the following reduces most entries but leaves Microsoft.AspNetCore.Hosting.Internal.WebHost at Information.

"Microsoft": "Information",
"Microsoft.AspNetCore.Mvc.Internal": "Warning",
"Microsoft.AspNetCore.Authentication":  "Warning"

Appologies if this doesn't work for log4net

If you're using Serilog to do your .NET Core logging, you can update your appsettings.json file to set the log levels like so:

"Serilog": {
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"Microsoft": "Error",
"System": "Error"
}
},
"Properties": {
"Application": "your-app"
}
}

This allows you to only log errors from System/Microsoft while logging everything else as you'd like.

What have really worked for me was adding this in ASP.NET Core 2.0 project's Startup.cs file:

using Microsoft.Extensions.Logging;
public void ConfigureServices(IServiceCollection services)
{
.
.
.


services.AddLogging(
builder =>
{
builder.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("NToastNotify", LogLevel.Warning)
.AddConsole();
});
}

This way you'll only get Warning level logs for logging info starting with the filters passed to builder.AddFilter.

My log4net.log file now doesn't show that huge amount of INFO logging spit by Microsoft and others.

More info here @ Microsoft Docs: Log filtering

Setting Logging.LogLevel in appsettings.json for the key Microsoft was not enough. I had to specifically set the following keys specifically, e.g.:

"Microsoft.Hosting.Lifetime": "Warning",
"Microsoft.AspNetCore.Hosting.Diagnostics": "Warning",
"Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware": "Warning"

But as an alternative using a key with a wildcard, e.g. Microsoft.*, worked. So I ended up with:

{
"Logging": {
"LogLevel": {
"Default":     "Warning",
"Microsoft.*": "Warning"
}
...
}

In ASP.NET Core version 3, you can clear the existing log providers in the ConfigureServices function:

public void ConfigureServices(IServiceCollection services) {
//Do everything else...
services.AddLogging(c => c.ClearProviders());
}

With Serilog, I found it was a simple case of specifying an override for Microsoft components when defining the logger configuration:

Log.Logger = new LoggerConfiguration()
... // Other config
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
... // Other config
.CreateLogger();

This allowed me to only log Warning level or above entries for Microsoft components, but Information and above for my own components.

Set these two configuration flags in the startup.cs

        services.ConfigureTelemetryModule<DependencyTrackingTelemetryModule>((module, options) =>
{
options.EnableDependencyTrackingTelemetryModule = false;
options.EnableRequestTrackingTelemetryModule = false;
});

then you will only see the trace telemetry type in the logs