Вы правы, что опубликованный вами код не работает. Этот код использует файл конфигурации (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») сообщение не было зарегистрировано.
И так, что здесь происходит? Если мы создаем экземпляр фильтра сами и добавляем его в конфигурацию, он работает, но при использовании конфигурации Enterprise Library значение фильтра не обновляется.
Это приводит к гипотезе: при использовании конфигурации Enterprise Library новые экземпляры фильтров возвращаются каждый раз, поэтому изменение значения не влияет на внутренний экземпляр, используемый Enterprise Library.
Если мы углубимся в код корпоративной библиотеки, мы (в конце концов) найдем 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()
, не влияют на внутреннюю конфигурацию, поскольку это новый экземпляр объекта, и, в любом случае, внутренняя Enterprise Library все равно создаст другой новый экземпляр при следующем Write()
вызове.
Во-первых, это просто неправильно, но также неэффективно создавать новые объекты при каждом вызове Write()
, который может быть вызван много раз ..
Простое решение этой проблемы - оценить перечисление LogFilters, вызвав ToList()
:
var filters = this.LogFilters.Select(tfd => tfd.BuildFilter()).ToList();
Это оценивает перечисление только один раз, гарантируя, что будет создан только один экземпляр фильтра. Тогда подход GetFilter()
и обновления значения фильтра, указанный в вопросе, будет работать.
person
Randy supports Monica
schedule
17.09.2016