英文:
Custom logger configurations overwritten by last configuration entry
问题
目前,我有两种类型的自定义日志记录器,它们都有自己的配置部分、ILoggerProvider 和 ILogger 实现。然而,似乎存在一个问题,即我的配置范围在将它们添加到我们的 ILoggingBuilder 时被读取为最后一个配置。
Appsetting 配置设置将被提取:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
},
"Logger1": {
"LogLevel": {
"Default": "Information"
},
"BenchmarkConfig": {
"Enable": true,
"LogThreshold": {
"Critical": "00:00:15",
"Information": "00:00:00"
}
}
},
"Logger2": {
"LogLevel": {
"Default": "Critical"
}
}
}
}
这是我在其中添加它们的 DI 层:
protected override void LoggingHook(IServiceCollection services, IConfiguration configuration)
{
base.LoggingHook(services, configuration);
_ = services.AddLogging(config => _ = config.AddLogger1(configuration));
_ = services.AddLogging(config => _ = config.AddLogger2(configuration));
}
Logger1
public static class Logger1Extensions
{
public static ILoggingBuilder AddLogger1(this ILoggingBuilder builder, IConfiguration configuration)
{
var configurationSection = configuration.GetSection(Logger1.Section);
_ = builder.AddConfiguration(configurationSection);
builder.Services.AddTransient<InitializedLogMessage>();
builder.Services.AddSingleton<ILogger1Config>(configurationSection.Get<Logger1Config>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, Logger1Provider>());
return builder;
}
}
public interface ILogger1Config
{
LogLevel LogLevel { get; set; }
Logger1BenchmarkConfig BenchmarkConfig { get; set; }
}
public class Logger1 : ILogger
{
private readonly ILambdaLogger _lambdaLogger;
private readonly ILogger1Config _loggerConfig;
public const string Section = "Logging:Logger1";
public const string SectionLogLevel = Section + ":LogLevel";
public const string SectionLogLevelDefault = SectionLogLevel + ":Default";
public Logger1(ILambdaLogger logger, ILogger1Config loggerConfig, InitializedLogMessage logMessage)
{
_lambdaLogger = logger;
_loggerConfig = loggerConfig;
LogMessage = logMessage;
}
private InitializedLogMessage LogMessage { get; }
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (IsEnabled(logLevel))
{
_lambdaLogger?.LogLine($"{GetScopePrefix()}[{logLevel}] {formatter(state, exception)}");
}
}
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
}
Logger2
public static class Logger2Extensions
{
public static ILoggingBuilder AddLogger2Generic<T>(this ILoggingBuilder builder,
IConfiguration configuration) where T : class, ILoggerProvider
{
IConfigurationSection section = configuration.GetSection("Logging:Logger2");
builder.AddConfiguration((IConfiguration) section);
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, T>());
return builder;
}
public static ILoggingBuilder AddLogger2(this ILoggingBuilder builder,
IConfiguration configuration)
{
return builder.AddLogger2Generic<Logger2Provider>(configuration);
}
}
public class Logger2 : ILogger
{
private _rest { get; set; }
public Logger2(IRest rest)
{
_rest = rest
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (IsEnabled(logLevel))
{
_rest.log()
}
}
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
}
如果我注释掉 Logger2Extensions.AddLogger2Generic 中的配置添加部分,那么 Logger1 中的一切都正常工作。但一旦将 Logger2 添加进来,它不仅会覆盖 Logger1 的配置,还会错误地读取日志级别。因为我正在使用来自 Microsoft 的日志级别枚举,所以它导致了默认的跟踪级别,因为它选择要转换为枚举的内容是无效的。
英文:
Currently, I have two types of custom loggers that both have their own configuration section, ILoggerProvider, and Ilogger implementation. However, it seems there is an issue with how my configuration scope is being read as the last configuration to be added during DI to our ILoggingBuilder.
Appsetting configuration settings that will get pulled
{
"Logging": {
"LogLevel": {
"Default": "Warning"
},
"Logger1": {
"LogLevel": {
"Default": "Information"
},
"BenchmarkConfig": {
"Enable": true,
"LogThreshold": {
"Critical": "00:00:15",
"Information": "00:00:00"
}
}
},
"Logger2": {
"LogLevel": {
"Default": "Critical"
}
}
}
}
This is the DI layer that I add them in
protected override void LoggingHook(IServiceCollection services, IConfiguration configuration)
{
base.LoggingHook(services, configuration);
_ = services.AddLogging(config => _ = config.AddLogger1(configuration));
_ = services.AddLogging(config => _ = config.AddLogger2(configuration));
}
Logger1
public static class Logger1Extensions
{
public static ILoggingBuilder AddLogger1(this ILoggingBuilder builder, IConfiguration configuration)
{
var configurationSection = configuration.GetSection(Logger1.Section);
_ = builder.AddConfiguration(configurationSection);
builder.Services.AddTransient<InitializedLogMessage>();
builder.Services.AddSingleton<ILogger1Config>(configurationSection.Get<Logger1Config>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, Logger1Provider>());
return builder;
}
}
public interface ILogger1Config
{
LogLevel LogLevel { get; set; }
Logger1BenchmarkConfig BenchmarkConfig { get; set; }
}
public class Logger1 : ILogger
{
private readonly ILambdaLogger _lambdaLogger;
private readonly ILogger1Config _loggerConfig;
public const string Section = "Logging:Logger1";
public const string SectionLogLevel = Section + ":LogLevel";
public const string SectionLogLevelDefault = SectionLogLevel + ":Default";
public Logger1(ILambdaLogger logger, ILogger1Config loggerConfig, InitializedLogMessage logMessage)
{
_lambdaLogger = logger;
_loggerConfig = loggerConfig;
LogMessage = logMessage;
}
private InitializedLogMessage LogMessage { get; }
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (IsEnabled(logLevel))
{
_lambdaLogger?.LogLine($"{GetScopePrefix()}[{logLevel}] {formatter(state, exception)}");
}
}
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
}
Logger2
public static class Logger2Extensions
{
public static ILoggingBuilder AddLogger2Generic<T>(this ILoggingBuilder builder,
IConfiguration configuration) where T : class, ILoggerProvider
{
IConfigurationSection section = configuration.GetSection("Logging:Logger2");
builder.AddConfiguration((IConfiguration) section);
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, T>());
return builder;
}
public static ILoggingBuilder AddLogger2(this ILoggingBuilder builder,
IConfiguration configuration)
{
return builder.AddLogger2Generic<Logger2Provider>(configuration);
}
}
public class Logger2 : ILogger
{
private _rest { get; set; }
public Logger2(IRest rest)
{
_rest = rest
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (IsEnabled(logLevel))
{
_rest.log()
}
}
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
}
If I comment out adding the configuration inside the Logger2Extesions.AddLogger2Generic then everything in Logger1 works fine. But once Logger2 is added into the mix it not only overwrites the configuration for Logger1 but it also reads the log level incorrectly. Since I am using the loglevel enum from microsoft it results in a defaulted loglevel of trace since what it picks up to cast to the enum is invalid.
答案1
得分: 1
在你的 AddLogger1
和 AddLogger2/AddLogger2Generic
方法中,你调用了 AddConfiguration
并提供了特定日志记录器的部分。 相反,你应该只调用 AddConfiguration
一次,仅一次,并提供 "Logging"
部分。 你还可以考虑在此之前调用 ClearProviders
。
尝试在添加其他日志记录器之前添加以下内容(并记得从这些方法中移除 AddConfiguration
调用):
services.AddLogging(config =>
{
_ = config.ClearProviders();
_ = config.AddConfiguration(configuration.GetSection("Logging"));
});
英文:
In your AddLogger1
and AddLogger2/AddLogger2Generic
methods, you are calling AddConfiguration
and providing the section for that specific logger. Instead, you should call AddConfiguration
once, and only once, and provide the "Logging"
section. You may also want to call ClearProviders
beforehand.
Try adding this before you add the other loggers (and remember to remove the AddConfiguration
calls from those other methods):
services.AddLogging(config =>
{
_ = config.ClearProviders();
_ = config.AddConfiguration(configuration.GetSection("Logging"));
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论