I want Administrators to enable/disable logging at runtime by changing the enabled property of the LogEnabledFilter in the config.
There are several threads on SO that explain workarounds, but I want it this way. I tried to change the Logging Enabled Filter like this:
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();
}
But test reveals always the initially loaded config value, it does not change. I thought, that when changing the value in the config the changes will be propagated automatically to the runtime configuration. But this isn't the case! Setting it programmatically as shown in the code above, doesn't work either.
It's time to rebuild Enterprise Library or shut it down.
You are right that the code you posted does not work. That code is using a config file (FileConfigurationSource) as the method to configure Enterprise Library.
Let's dig a bit deeper and see if programmatic configuration will work.
We will use the Fluent API since it is the preferred method for programmatic configuration:
If you try this code the filter will not be updated -- so another failure.
Let's try to use the "old school" programmatic configuration by using the classes directly:
Success! The second ("Test2") message was not logged.
So, what is going on here? If we instantiate the filter ourselves and add it to the configuration it works but when relying on the Enterprise Library configuration the filter value is not updated.
This leads to a hypothesis: when using Enterprise Library configuration new filter instances are being returned each time which is why changing the value has no effect on the internal instance being used by Enterprise Library.
If we dig into the Enterprise Library code we (eventually) hit on
LoggingSettingsclass and theBuildLogWritermethod. This is used to create the LogWriter. Here's where the filters are created:So this line is using the configured
LogFilterDataand calling the BuildFilter method to instantiate the applicable filter. In this case theBuildFiltermethod of the configuration classLogEnabledFilterDataBuildFiltermethod returns an instance of theLogEnabledFilter:The issue with this code is that
this.LogFilters.Selectreturns a lazy evaluated enumeration that createsLogFiltersand this enumeration is passed into the LogWriter to be used for all filter manipulation. Every time the filters are referenced the enumeration is evaluated and a new Filter instance is created! This confirms the original hypothesis.To make it explicit: every time LogWriter.Write() is called a new
LogEnabledFilteris created based on the original configuration. When the filters are queried by callingGetFilter()a newLogEnabledFilteris created based on the original configuration. Any changes to the object returned byGetFilter()have no affect on the internal configuration since it's a new object instance and, anyway, internally Enterprise Library will create another new instance on the nextWrite()call anyway.Firstly, this is just plain wrong but it is also inefficient to create new objects on every call to
Write()which could be invoked many times..An easy fix for this issue is to evaluate the LogFilters enumeration by calling
ToList():This evaluates the enumeration only once ensuring that only one filter instance is created. Then the
GetFilter()and update filter value approach posted in the question will work.