在 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方法配置classLogEnabledFilterDataBuildFilter方法returns实例LogEnabledFilter:

return new LogEnabledFilter(this.Name, this.Enabled);

此代码的问题是 this.LogFilters.Select returns 一个创建 LogFilters 的惰性评估枚举,并且此枚举被传递到 LogWriter 以用于所有过滤器操作。 每次引用过滤器时,都会评估枚举并创建一个新的过滤器实例!这证实了最初的假设。

明确地说:每次调用 LogWriter.Write() 时都会根据原始配置创建新的 LogEnabledFilter。当通过调用 GetFilter() 查询过滤器时,会根据原始配置创建一个新的 LogEnabledFilterGetFilter() 返回的对象的任何更改都不会影响内部配置,因为它是一个新的对象实例,无论如何,Enterprise Library 内部将在下一个 Write() 调用时创建另一个新实例。

首先,这完全是错误的,但在每次调用 Write() 时创建新对象也是低效的,因为 Write() 可以多次调用..

此问题的一个简单解决方法是通过调用 ToList():

来评估 LogFilters 枚举
var filters = this.LogFilters.Select(tfd => tfd.BuildFilter()).ToList();

这只对枚举求值一次,确保只创建一个过滤器实例。然后问题中发布的 GetFilter() 和更新过滤器值方法将起作用。