在 FileConfigurationSourceChanged 上禁用日志记录 - LogEnabledFilter
Disable logging on FileConfigurationSourceChanged - LogEnabledFilter
我希望管理员 enable/disable 通过更改配置中 LogEnabledFilter 的启用 属性 在运行时记录。
SO 上有几个线程解释了解决方法,但我希望这样。
我尝试像这样更改启用日志记录的过滤器:
private static void FileConfigurationSourceChanged(object sender, ConfigurationSourceChangedEventArgs e)
{
var fcs = sender as FileConfigurationSource;
System.Diagnostics.Debug.WriteLine("----------- FileConfigurationSourceChanged called --------");
LoggingSettings currentLogSettings = e.ConfigurationSource.GetSection("loggingConfiguration") as LoggingSettings;
var fdtl = currentLogSettings.TraceListeners.Where(tld => tld is FormattedDatabaseTraceListenerData).FirstOrDefault();
var currentLogFileFilter = currentLogSettings.LogFilters.Where(lfd => { return lfd.Name == "Logging Enabled Filter"; }).FirstOrDefault();
var filterNewValue = (bool)currentLogFileFilter.ElementInformation.Properties["enabled"].Value;
var runtimeFilter = Logger.Writer.GetFilter<LogEnabledFilter>("Logging Enabled Filter");
runtimeFilter.Enabled = filterNewValue;
var test = Logger.Writer.IsLoggingEnabled();
}
但是测试总是显示初始加载的配置值,它不会改变。
我想,当更改配置中的值时,更改将自动传播到运行时配置。但事实并非如此!
如上面的代码所示以编程方式设置它也不起作用。
是时候重建企业图书馆或将其关闭了。
更新:
Randy Levy 在他上面的回答中提供了一个修复。
实施修复并重新编译企业库。
以下是 Randy Levy 的回答:
Yes, you can disable logging by setting the LogEnabledFiter. The main
way to do this would be to manually edit the configuration file --
this is the main intention of that functionality (developers guide
references administrators tweaking this setting). Other similar
approaches to setting the filter are to programmatically modify the
original file-based configuration (which is essentially a
reconfiguration of the block), or reconfigure the block
programmatically (e.g. using the fluent interface). None of the
programmatic approaches are what I would call simple – Randy Levy 39
mins ago
If you try to get the filter and disable it I don't think it has any
affect without a reconfiguration. So the following code still ends up
logging: var enabledFilter = logWriter.GetFilter();
enabledFilter.Enabled = false; logWriter.Write("TEST"); One non-EntLib
approach would just to manage the enable/disable yourself with a bool
property and a helper class. But I think the priority approach is a
pretty straight forward alternative.
结论:
在您的自定义记录器中 class 在运行时实现 IsLoggenabled 属性 和 change/check 这个。
这行不通:
var runtimeFilter = Logger.Writer.GetFilter<LogEnabledFilter>("Logging Enabled Filter");
runtimeFilter.Enabled = false/true;
您说得对,您发布的代码不起作用。该代码使用配置文件 (FileConfigurationSource) 作为配置企业库的方法。
让我们深入研究一下,看看编程配置是否可行。
我们将使用 Fluent API,因为它是编程配置的首选方法:
var builder = new ConfigurationSourceBuilder();
builder.ConfigureLogging()
.WithOptions
.DoNotRevertImpersonation()
.FilterEnableOrDisable("EnableOrDisable").Enable()
.LogToCategoryNamed("General")
.WithOptions.SetAsDefaultCategory()
.SendTo.FlatFile("FlatFile")
.ToFile(@"fluent.log");
var configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace(configSource);
var defaultWriter = new LogWriterFactory(configSource).Create();
defaultWriter.Write("Test1", "General");
var filter = defaultWriter.GetFilter<LogEnabledFilter>();
filter.Enabled = false;
defaultWriter.Write("Test2", "General");
如果您尝试此代码,过滤器将不会更新 -- 又一次失败。
让我们尝试通过直接使用 classes 来使用 "old school" 编程配置:
var flatFileTraceListener = new FlatFileTraceListener(
@"program.log",
"----------------------------------------",
"----------------------------------------"
);
LogEnabledFilter enabledFilter = new LogEnabledFilter("Logging Enabled Filter", true);
// Build Configuration
var config = new LoggingConfiguration();
config.AddLogSource("General", SourceLevels.All, true)
.AddTraceListener(flatFileTraceListener);
config.Filters.Add(enabledFilter);
LogWriter defaultWriter = new LogWriter(config);
defaultWriter.Write("Test1", "General");
var filter = defaultWriter.GetFilter<LogEnabledFilter>();
filter.Enabled = false;
defaultWriter.Write("Test2", "General");
成功!第二条 ("Test2") 消息未记录。
那么,这是怎么回事?如果我们自己实例化过滤器并将其添加到配置中,它会起作用,但是当依赖企业库配置时,过滤器值不会更新。
这导致了一个假设:当使用企业库配置时,每次都会返回新的过滤器实例,这就是为什么更改值对企业库使用的内部实例没有影响。
如果我们深入研究企业库代码,我们(最终)会找到 LoggingSettings
class 和 BuildLogWriter
方法。这用于创建 LogWriter。这里是创建过滤器的地方:
var filters = this.LogFilters.Select(tfd => tfd.BuildFilter());
所以这一行使用配置的 LogFilterData
并调用 BuildFilter 方法来实例化适用的过滤器。本例BuildFilter
方法配置classLogEnabledFilterData
BuildFilter
方法returns实例LogEnabledFilter
:
return new LogEnabledFilter(this.Name, this.Enabled);
此代码的问题是 this.LogFilters.Select
returns 一个创建 LogFilters
的惰性评估枚举,并且此枚举被传递到 LogWriter 以用于所有过滤器操作。 每次引用过滤器时,都会评估枚举并创建一个新的过滤器实例!这证实了最初的假设。
明确地说:每次调用 LogWriter.Write() 时都会根据原始配置创建新的 LogEnabledFilter
。当通过调用 GetFilter()
查询过滤器时,会根据原始配置创建一个新的 LogEnabledFilter
。 GetFilter()
返回的对象的任何更改都不会影响内部配置,因为它是一个新的对象实例,无论如何,Enterprise Library 内部将在下一个 Write()
调用时创建另一个新实例。
首先,这完全是错误的,但在每次调用 Write()
时创建新对象也是低效的,因为 Write()
可以多次调用..
此问题的一个简单解决方法是通过调用 ToList()
:
来评估 LogFilters 枚举
var filters = this.LogFilters.Select(tfd => tfd.BuildFilter()).ToList();
这只对枚举求值一次,确保只创建一个过滤器实例。然后问题中发布的 GetFilter()
和更新过滤器值方法将起作用。
我希望管理员 enable/disable 通过更改配置中 LogEnabledFilter 的启用 属性 在运行时记录。
SO 上有几个线程解释了解决方法,但我希望这样。 我尝试像这样更改启用日志记录的过滤器:
private static void FileConfigurationSourceChanged(object sender, ConfigurationSourceChangedEventArgs e)
{
var fcs = sender as FileConfigurationSource;
System.Diagnostics.Debug.WriteLine("----------- FileConfigurationSourceChanged called --------");
LoggingSettings currentLogSettings = e.ConfigurationSource.GetSection("loggingConfiguration") as LoggingSettings;
var fdtl = currentLogSettings.TraceListeners.Where(tld => tld is FormattedDatabaseTraceListenerData).FirstOrDefault();
var currentLogFileFilter = currentLogSettings.LogFilters.Where(lfd => { return lfd.Name == "Logging Enabled Filter"; }).FirstOrDefault();
var filterNewValue = (bool)currentLogFileFilter.ElementInformation.Properties["enabled"].Value;
var runtimeFilter = Logger.Writer.GetFilter<LogEnabledFilter>("Logging Enabled Filter");
runtimeFilter.Enabled = filterNewValue;
var test = Logger.Writer.IsLoggingEnabled();
}
但是测试总是显示初始加载的配置值,它不会改变。 我想,当更改配置中的值时,更改将自动传播到运行时配置。但事实并非如此! 如上面的代码所示以编程方式设置它也不起作用。
是时候重建企业图书馆或将其关闭了。
更新:
Randy Levy 在他上面的回答中提供了一个修复。 实施修复并重新编译企业库。
以下是 Randy Levy 的回答:
Yes, you can disable logging by setting the LogEnabledFiter. The main way to do this would be to manually edit the configuration file -- this is the main intention of that functionality (developers guide references administrators tweaking this setting). Other similar approaches to setting the filter are to programmatically modify the original file-based configuration (which is essentially a reconfiguration of the block), or reconfigure the block programmatically (e.g. using the fluent interface). None of the programmatic approaches are what I would call simple – Randy Levy 39 mins ago
If you try to get the filter and disable it I don't think it has any affect without a reconfiguration. So the following code still ends up logging: var enabledFilter = logWriter.GetFilter(); enabledFilter.Enabled = false; logWriter.Write("TEST"); One non-EntLib approach would just to manage the enable/disable yourself with a bool property and a helper class. But I think the priority approach is a pretty straight forward alternative.
结论:
在您的自定义记录器中 class 在运行时实现 IsLoggenabled 属性 和 change/check 这个。
这行不通:
var runtimeFilter = Logger.Writer.GetFilter<LogEnabledFilter>("Logging Enabled Filter");
runtimeFilter.Enabled = false/true;
您说得对,您发布的代码不起作用。该代码使用配置文件 (FileConfigurationSource) 作为配置企业库的方法。
让我们深入研究一下,看看编程配置是否可行。
我们将使用 Fluent API,因为它是编程配置的首选方法:
var builder = new ConfigurationSourceBuilder();
builder.ConfigureLogging()
.WithOptions
.DoNotRevertImpersonation()
.FilterEnableOrDisable("EnableOrDisable").Enable()
.LogToCategoryNamed("General")
.WithOptions.SetAsDefaultCategory()
.SendTo.FlatFile("FlatFile")
.ToFile(@"fluent.log");
var configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace(configSource);
var defaultWriter = new LogWriterFactory(configSource).Create();
defaultWriter.Write("Test1", "General");
var filter = defaultWriter.GetFilter<LogEnabledFilter>();
filter.Enabled = false;
defaultWriter.Write("Test2", "General");
如果您尝试此代码,过滤器将不会更新 -- 又一次失败。
让我们尝试通过直接使用 classes 来使用 "old school" 编程配置:
var flatFileTraceListener = new FlatFileTraceListener(
@"program.log",
"----------------------------------------",
"----------------------------------------"
);
LogEnabledFilter enabledFilter = new LogEnabledFilter("Logging Enabled Filter", true);
// Build Configuration
var config = new LoggingConfiguration();
config.AddLogSource("General", SourceLevels.All, true)
.AddTraceListener(flatFileTraceListener);
config.Filters.Add(enabledFilter);
LogWriter defaultWriter = new LogWriter(config);
defaultWriter.Write("Test1", "General");
var filter = defaultWriter.GetFilter<LogEnabledFilter>();
filter.Enabled = false;
defaultWriter.Write("Test2", "General");
成功!第二条 ("Test2") 消息未记录。
那么,这是怎么回事?如果我们自己实例化过滤器并将其添加到配置中,它会起作用,但是当依赖企业库配置时,过滤器值不会更新。
这导致了一个假设:当使用企业库配置时,每次都会返回新的过滤器实例,这就是为什么更改值对企业库使用的内部实例没有影响。
如果我们深入研究企业库代码,我们(最终)会找到 LoggingSettings
class 和 BuildLogWriter
方法。这用于创建 LogWriter。这里是创建过滤器的地方:
var filters = this.LogFilters.Select(tfd => tfd.BuildFilter());
所以这一行使用配置的 LogFilterData
并调用 BuildFilter 方法来实例化适用的过滤器。本例BuildFilter
方法配置classLogEnabledFilterData
BuildFilter
方法returns实例LogEnabledFilter
:
return new LogEnabledFilter(this.Name, this.Enabled);
此代码的问题是 this.LogFilters.Select
returns 一个创建 LogFilters
的惰性评估枚举,并且此枚举被传递到 LogWriter 以用于所有过滤器操作。 每次引用过滤器时,都会评估枚举并创建一个新的过滤器实例!这证实了最初的假设。
明确地说:每次调用 LogWriter.Write() 时都会根据原始配置创建新的 LogEnabledFilter
。当通过调用 GetFilter()
查询过滤器时,会根据原始配置创建一个新的 LogEnabledFilter
。 GetFilter()
返回的对象的任何更改都不会影响内部配置,因为它是一个新的对象实例,无论如何,Enterprise Library 内部将在下一个 Write()
调用时创建另一个新实例。
首先,这完全是错误的,但在每次调用 Write()
时创建新对象也是低效的,因为 Write()
可以多次调用..
此问题的一个简单解决方法是通过调用 ToList()
:
var filters = this.LogFilters.Select(tfd => tfd.BuildFilter()).ToList();
这只对枚举求值一次,确保只创建一个过滤器实例。然后问题中发布的 GetFilter()
和更新过滤器值方法将起作用。