2016-09-16 4 views
1

Я хочу, чтобы администраторы включали/запрещали ведение журнала во время выполнения, изменяя включенное свойство LogEnabledFilter в config.Отключить ведение журнала на FileConfigurationSourceChanged - LogEnabledFilter

Есть несколько потоков на SO, которые объясняют обходные пути, но я хочу это так. Я попытался изменить Logging Enabled фильтра так:

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

} 

Но тест показывает всегда первоначально загруженное значение конфигурации, это не меняет. Я думал, что при изменении значения в конфигурации изменения будут автоматически передаваться в конфигурацию времени выполнения. Но это не так! Установка программно, как показано в приведенном выше коде, также не работает.

Пришло время перестроить корпоративную библиотеку или закрыть ее.

ответ

1

Вы правы, что код размещен не работает.Этот код использует файл конфигурации (FileConfigurationSource) в качестве метода настройки Enterprise Library.

Давайте углубимся глубже и посмотрим, будет ли работать программная конфигурация.

Мы будем использовать 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 новые экземпляры фильтров возвращаются каждый раз, поэтому изменение значения не влияет на внутренний экземпляр, используемый корпоративной библиотекой.

Если мы копаем код корпоративной библиотеки, мы (в конечном итоге) нажимаем на класс LoggingSettings и метод BuildLogWriter. Это используется для создания LogWriter. Вот где создаются фильтры:

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

Так эта линия использует сконфигурированный LogFilterData и вызов метода BuildFilter для создания экземпляра применимого фильтра. В этом случае BuildFilter метод класса конфигурации LogEnabledFilterDataBuildFilter метода возвращает экземпляр 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() и значение фильтра обновления, опубликованное в вопросе.

+0

Рэнди, спасибо за подробное объяснение! Я загрузил последний исходный код для EL6, и я реализовал это исправление, но я не могу создать исходный код, используя BuildLibrary.bat в своей системе. Не могли бы вы взглянуть на этот вопрос (http://stackoverflow.com/questions/39546020/how-to-rebuild-enterprise-library-6-on-win-8-and-vs2015) – Legends

+0

Хорошо, сделанный. Я получил его для работы, используя ваше исправление. Большое спасибо! – Legends

+1

FYI, после исправления, я повторно запустил тесты Unit и BVT и не видел никаких повреждений из-за изменения. –

0

Update:

Рэнди Леви предоставил исправление в своем ответе выше. Внедрите исправление и перекомпилируйте корпоративную библиотеку.

Вот ответ от Рэнди Леви:

Да, вы можете отключить запись, установив LogEnabledFiter. Основным способом сделать это было бы вручную отредактировать файл конфигурации - Это основная цель этой функциональности (руководство разработчиков ссылается на администраторов, настраивающих эту настройку). Другие аналогичные подходы к настройке фильтра - программно изменить исходную конфигурацию на основе файлов (которая по существу является реконфигурацией блока ) или программным образом перенастроить блок (например, используя свободный интерфейс). Ни один из программных подходов не то, что я бы назвал просто - Рэнди Леви 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; 
Смежные вопросы