所以我有一个基本的自定义记录器,并按以下步骤进行设置:
public static IWebHost CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseIISIntegration()
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole();
logging.AddCustomLogger().AddFilter<CustomLoggerProvider>(typeof(CustomLogEntry).ToString(), LogLevel.None); // My custom logger
logging.SetMinimumLevel(LogLevel.Trace);
}).Build();
}
我的理解是,.AddFilter意味着仅记录器的
typeof(CustomLogEntry)
实际上应该注销到我的自定义记录器。不过,事实似乎并非如此!
添加实际记录器的扩展名非常简单:
public static ILoggingBuilder AddCustomLogger(this ILoggingBuilder builder)
{
builder.AddConfiguration();
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, CustomLoggerProvider>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<CustomLoggerOptions>, CustomLoggerOptionsSetup>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IOptionsChangeTokenSource<LoggerOptions>, CustomLoggerProviderOptionsChangeTokenSource<CustomLoggerOptions, CustomLoggerProvider>>());
return builder;
}
我的自定义记录器也非常简单:
public class CustomLogger : ILogger
{
public CustomLoggerProvider Provider { get; private set; }
public string Category { get; private set; }
public Logger(CustomLoggerProvider provider, string category)
{
Provider = provider;
Category = category;
}
public IDisposable BeginScope<T>(T item)
{
return Provider.ScopeProvider.Push(item);
}
public bool IsEnabled(LogLevel logLevel)
{
return Provider.IsEnabled(logLevel);
}
public void Log<T>(LogLevel logLevel, EventId eventId, T item, Exception exception, Func<T, Exception, string> formatter)
{
if (IsEnabled(logLevel))
{
// Generate the log entry
CustomLogEntry logEntry = new CustomLogEntry();
// removed for brevity...
// Write the log out to the provider!
Provider.WriteLog(logEntry);
}
}
}
和提供者:
[ProviderAlias("Custom")]
public class CustomLoggerProvider : ILoggerProvider, IDisposable, ISupportExternalScope
{
private ConcurrentQueue<CustomLogEntry> _logQueue = new ConcurrentQueue<CustomLogEntry>();
private readonly IDisposable _settingsChangeToken;
private readonly CustomLogger _customLogger;
private CustomLoggerOptions _settings;
private bool _terminated = false;
public IExternalScopeProvider ScopeProvider { get; set; }
public CustomLoggerProvider(IOptionsMonitor<LoggerOptions> settings, IConfiguration configuration) : this(settings.CurrentValue, configuration)
{
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/change-tokens
_settingsChangeToken = settings.OnChange(options =>
{
_settings = options;
});
}
public CustomLoggerProvider(CustomLoggerOptions settings, IConfiguration configuration)
{
_settings = settings;
_customLogger = new CustomLogger(this, typeof(CustomLogEntry).ToString());
ProcessQueue();
}
public ILogger CreateLogger(string categoryName)
{
return _customLogger;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel == LogLevel.Information;
}
public void WriteLog(LogEntry logEntry)
{
_logQueue.Enqueue(logEntry);
}
private void ProcessQueue()
{
Task.Run(async () =>
{
while (!_terminated)
{
try
{
// chew up the queue
if (_logQueue.TryDequeue(out CustomLogEntry logEntry))
{
// Do work, removed for brevity
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
});
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
_terminated = true;
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
disposedValue = true;
}
}
// This code added to correctly implement the disposable pattern.
void IDisposable.Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
}
#endregion
#region ISupportExternalScope Support
public void SetScopeProvider(IExternalScopeProvider scopeProvider)
{
ScopeProvider = scopeProvider;
}
#endregion
}
因此,在将它们放在一起并进行了测试之后,我看到每个LogLevel.Trace或更高版本的日志都记录到CustomLogger中。
我想做的是,只有特定类别的日志实际注销到自定义提供程序。或者换句话说,根据类别过滤要注销的日志提供程序。
我无法做到吗?我是否会误解.AddFilter实际如何工作? (可能是,哈哈)
我怀疑我的CustomLoggerProvider.IsEnabled某种程度上需要检查传入的日志类别是否正确,但我只是不知道如何实现此目的。
我将不胜感激任何指针。
AddFilter
的第一个参数是要应用它的名称空间。目前,您正在传递nameof(CustomLogEntry)
,该命令将无法使用。实质上,这就是说only
所以这就是我最终要做的: