2016-09-16 1 views
1

Ich möchte, dass Administratoren die Protokollierung zur Laufzeit aktivieren/deaktivieren, indem sie die Eigenschaft enabled des LogEnabledFilter in der Konfiguration ändern.Deaktivieren der Protokollierung von FileConfigurationSourceChanged - LogEnabledFilter

Es gibt mehrere Threads auf SO, die Workarounds erklären, aber ich möchte es auf diese Weise. Ich versuchte, die Protokollierung aktiviert Filter wie folgt zu ändern:

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

} 

Aber Test zeigt immer die anfänglich Config-Wert geladen, es ändert sich nicht. Ich dachte, dass die Änderungen bei der Änderung des Wertes in der Config automatisch in die Runtime-Konfiguration übernommen werden. Aber das ist nicht der Fall! Die programmgesteuerte Einstellung, wie im obigen Code gezeigt, funktioniert auch nicht.

Es ist Zeit, die Enterprise Library neu zu erstellen oder sie herunterzufahren.

Antwort

1

Sie haben Recht, dass der Code nicht geschrieben funktioniert.Dieser Code verwendet eine Konfigurationsdatei (FileConfigurationSource) als Methode zum Konfigurieren der Enterprise Library.

Lassen Sie uns ein wenig tiefer graben und sehen, ob die programmatische Konfiguration funktioniert.

Wir werden die Fluent API verwenden, da es die bevorzugte Methode zur programmatischen Konfiguration ist:

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

Wenn Sie versuchen, diesen Code wird der Filter nicht aktualisiert werden - so ein weiteres Scheitern.

Lassen Sie uns versuchen, die „alten Schule“ programmatische Konfiguration zu verwenden, indem die Klassen direkt mit:

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

Erfolg! Die zweite Nachricht ("Test2") wurde nicht protokolliert.

Also, was ist hier los? Wenn wir den Filter selbst instanziieren und ihn zur Konfiguration hinzufügen, funktioniert der Filterwert nicht, wenn er sich auf die Enterprise Library-Konfiguration verlässt.

Dies führt zu einer Hypothese: Bei der Verwendung der Enterprise Library-Konfiguration werden jedes Mal neue Filterinstanzen zurückgegeben. Daher hat das Ändern des Werts keine Auswirkungen auf die von Enterprise Library verwendete interne Instanz.

Wenn wir in den Enterprise Library Code graben wir (schließlich) auf LoggingSettings Klasse und die BuildLogWriter Methode. Dies wird verwendet, um den LogWriter zu erstellen. Hier ist, wo die Filter erstellt werden:

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

So diese Linie die konfigurierte LogFilterData verwendet, und den Aufruf der BuildFilter Methode des anwendbaren Filter zu instanziiert. In diesem Fall wird die BuildFilter Methode der Konfigurationsklasse LogEnabledFilterDataBuildFilter Methode gibt eine Instanz der LogEnabledFilter:

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

Das Problem mit diesem Code ist, dass this.LogFilters.Select eine faule ausgewertete Aufzählung zurückzugibt, die LogFilters und diese Aufzählung erzeugt wird geführt in der LogWriter, der für alle Filtermanipulationen verwendet werden soll. Jedes Mal, wenn auf die Filter verwiesen wird, wird die Aufzählung ausgewertet und eine neue Filterinstanz erstellt! Dies bestätigt die ursprüngliche Hypothese.

Um es explizit zu machen: Jedes Mal, wenn LogWriter.Write() aufgerufen wird, wird ein neues LogEnabledFilter basierend auf der ursprünglichen Konfiguration erstellt. Wenn die Filter durch Aufruf von GetFilter() abgefragt werden, wird basierend auf der ursprünglichen Konfiguration ein neuer LogEnabledFilter erstellt. Alle Änderungen am Objekt, die von GetFilter() zurückgegeben werden, haben keine Auswirkungen auf die interne Konfiguration, da es sich um eine neue Objektinstanz handelt und die Enterprise Library auf jeden Fall eine weitere neue Instanz auf dem nächsten Write()-Aufruf erstellt.

Erstens ist das einfach falsch, aber es ist auch ineffizient, neue Objekte bei jedem Aufruf an Write() zu erstellen, der mehrmals aufgerufen werden konnte.

Eine einfache Lösung für dieses Problem ist es, die LogFilters Aufzählung zu bewerten ToList() durch den Aufruf:

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

Dies wertet die Aufzählung sichergestellt nur einmal, dass nur eine Filterinstanz erstellt wird. Dann funktioniert der GetFilter() und Update-Filterwert-Ansatz in der Frage funktioniert.

+0

Randy, danke für die ausführliche Erklärung! Ich habe den neuesten Quellcode für EL6 heruntergeladen, und ich habe dieses Update implementiert, aber ich kann den Quellcode nicht mit der BuildLibrary.bat auf meinem System erstellen. Könnten Sie bitte einen Blick auf diese [Frage] nehmen (http://stackoverflow.com/questions/39546020/how-to-rebuild-enterprise-library-6-on-win-8-and-vs2015) – Legends

+0

Ok, erledigt. Ich habe es mit deiner Reparatur funktionieren lassen. Danke vielmals! – Legends

+1

FYI, nach der Reparatur habe ich die Unit- und BVT-Tests erneut durchgeführt und sah keinen Bruch aufgrund der Änderung. –

0

Update:

Randy Levy bot eine fix in seiner Antwort oben. Implementieren Sie das Update und kompilieren Sie die Enterprise-Bibliothek neu. Hier

ist die Antwort von Randy Levy:

Ja, Sie können die Protokollierung deaktivieren, indem Sie die LogEnabledFiter Einstellung. Die Hauptmethode wäre, die Konfigurationsdatei manuell zu bearbeiten - Dies ist die Hauptabsicht dieser Funktionalität (Entwicklerhandbuch verweist auf Administratoren, die diese Einstellung optimieren). Andere ähnliche Ansätze zum Einstellen des Filters sind, die ursprüngliche dateibasierte Konfiguration (die im Wesentlichen eine Neukonfiguration des Blocks ist) programmgesteuert zu ändern, oder den Block programmgesteuert neu zu konfigurieren (z. B. unter Verwendung der fließenden Schnittstelle). Keiner der programmatischen Ansätze ist, was ich nennen würde einfach - Randy Levy 39 Minuten vor


Wenn Sie versuchen, die Filter zu bekommen, und es deaktivieren Ich glaube nicht, ob sie für ein beeinflussen ohne eine Neukonfiguration. Also der folgende Code endet immer noch Protokollierung: var enabledFilter = logWriter.GetFilter(); enabledFilter.Enabled = false; logWriter.Write ("TEST"); Ein Nicht-EntLib Ansatz würde nur die Aktivierung/Deaktivierung mit einer bool Eigenschaft und einer Hilfsklasse verwalten. Aber ich denke, der Prioritätsansatz ist eine ziemlich einfache Alternative.

Fazit:

In Ihrer benutzerdefinierten Logger-Klasse implementieren eine IsLoggenabled Eigenschaft und ändern/überprüfen Sie diese zur Laufzeit.

arbeiten Dies wird nicht:

var runtimeFilter = Logger.Writer.GetFilter<LogEnabledFilter>("Logging Enabled Filter"); 
runtimeFilter.Enabled = false/true; 
Verwandte Themen