1

我希望管理员在运行时通过更改配置中 LogEnabledFilter 的 enabled 属性来启用/禁用日志记录。

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();

}

但是测试总是显示最初加载的配置值,它不会改变。我认为,当更改配置中的值时,更改将自动传播到运行时配置。但事实并非如此!如上面的代码所示以编程方式设置它也不起作用。

是时候重建 Enterprise Library 或将其关闭了。

4

2 回答 2

1

您是对的,您发布的代码不起作用。该代码使用配置文件 (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");

如果您尝试使用此代码,则过滤器将不会更新——因此会再次失败。

让我们尝试通过直接使用类来使用“老派”编程配置:

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类和BuildLogWriter方法。这用于创建 LogWriter。这是创建过滤器的位置:

var filters = this.LogFilters.Select(tfd => tfd.BuildFilter());

所以这一行正在使用配置LogFilterData并调用 BuildFilter 方法来实例化适用的过滤器。在这种情况下BuildFilter,配置类LogEnabledFilterData BuildFilter方法的方法返回一个实例LogEnabledFilter

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

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

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

首先,这完全是错误的,但在每次调用时创建新对象也效率低下,这些对象Write()可能会被多次调用。

解决此问题的一个简单方法是通过调用来评估 LogFilters 枚举ToList()

var filters = this.LogFilters.Select(tfd => tfd.BuildFilter()).ToList();

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

于 2016-09-17T01:01:39.737 回答
0

更新:

Randy Levy 在上面的回答中提供了解决方案。实施修复并重新编译企业库。

这是兰迪·利维的回答:

是的,您可以通过设置 LogEnabledFiter 来禁用日志记录。执行此操作的主要方法是手动编辑配置文件——这是该功能的主要目的(开发人员指南参考管理员调整此设置)。设置过滤器的其他类似方法是以编程方式修改基于文件的原始配置(本质上是对块的重新配置),或以编程方式重新配置块(例如使用流利界面​​)。没有一种程序化方法是我所说的简单——Randy Levy 39 分钟前


如果您尝试获取过滤器并禁用它,我认为如果不重新配置它不会有任何影响。所以下面的代码仍然会记录日志: var enabledFilter = logWriter.GetFilter(); enabledFilter.Enabled = false; logWriter.Write("TEST"); 一种非 EntLib 方法只是使用 bool 属性和帮助程序类来管理自己的启用/禁用。但我认为优先方法是一个非常直接的选择。

结论:

在您的自定义 Logger 类中实现 IsLoggenabled 属性并在运行时更改/检查该属性。

这不起作用:

var runtimeFilter = Logger.Writer.GetFilter<LogEnabledFilter>("Logging Enabled Filter");
runtimeFilter.Enabled = false/true;
于 2016-09-16T20:09:53.340 回答