2012-05-14 20 views
15

Ich suche nach einer Möglichkeit, einen TraceListener für alle vorhandenen TraceSources hinzuzufügen und zu entfernen.TraceListener zu allen TraceSources hinzufügen/entfernen

(Ich bin mir nicht sicher, ob mein Ansatz hier richtig ist, welche anderen Möglichkeiten könnte ich verwenden? Grundsätzlich möchte ich alle Trace-Ausgabe in eine Datei protokollieren, die den aktuellen Projektnamen als Dateiname verwendet. Wann immer ein Benutzer erstellt oder wieder öffnet Projekt möchte ich Protokolle auf die richtige Datei anhängen Es gibt nur zu einem Zeitpunkt ein Projekt geöffnet sein kann)

Code-Beispiel:..

ich mehrere Trace in meiner Anwendung erstellen, eine für jede Klasse

public class Class1 
{ 
    private static readonly System.Diagnostics.TraceSource trace = 
      new System.Diagnostics.TraceSource("Class1"); 
} 

public class Class2 
{ 
    private static readonly System.Diagnostics.TraceSource trace = 
      new System.Diagnostics.TraceSource("Class2"); 
} 

Ich möchte jetzt hinzufügen oder eine Tracelistener, um alle meine Trace zur Laufzeit, wie diese entfernen:

private System.Diagnostics.TextWriterTraceListener myListener; 

private onProjectOpen() 
{ 
    // user created a new project or opened an existing one 
    myListener = new System.Diagnostics.TextWriterTraceListener("log-"+projectname+".log"); 
    ALL_TRACESOURCES.Add (myListener) ; // <-- how to do this? 
} 

private onProjectClose() 
{ 
    // user closed a project 
    ALL_TRACESOURCES.Remove(myListener) ; // <-- how to do this? 
    myListener.Flush(); 
    myListener.Close(); 
    myListener.Dispose(); // <-- not sure if all this is neccessary 
} 

Bisher fand ich keine Möglichkeit, dies zu tun, ohne alle öffentlichen meine Trace zu machen (wie eine schlechte Idee scheint) und dann auflisten alle meine Klassen wie folgt:

Class1.Trace.Add(myListener); 
Class2.Trace.Add(myListener); 
... 

die scheint wie eine schlechte Design-Wahl auf mehreren Ebenen.

Oder

hinzufügen alle meine Trace zu einer benutzerdefinierten globalen Sammlung im Konstruktor jeder Klasse (leicht zu vergessen/mess up und globale Variablen sind schlecht)

Gibt es einen besseren Weg? Im Grunde bin ich auf der Suche nach einer Möglichkeit, einen anderen Standard-Listener

Antwort

0

In .NET 4 und höher können Sie Lazy<> verwenden, um Ihre TraceSources lazy-load nach Hörer konfiguriert wurden. Siehe folgendes Arbeitsbeispiel:

public static class TraceSources 
{ 
    public static TraceSource Create(string sourceName) 
    { 
     var source = new TraceSource(sourceName); 
     source.Listeners.AddRange(Trace.Listeners); 
     source.Switch.Level = SourceLevels.All; 
     return source; 
    } 
} 

public class Class1 
{ 
    private static readonly Lazy<TraceSource> trace = new 
      Lazy<TraceSource>(() => TraceSources.Create("Class1")); 

    public void DoSomething() 
    { 
     trace.Value.TraceEvent(TraceEventType.Information, 1, "Class1 speaking up"); 
    } 
} 

public class Class2 
{ 
    private static readonly Lazy<TraceSource> trace = new 
      Lazy<TraceSource>(() => TraceSources.Create("Class2")); 

    public void DoSomethingElse() 
    { 
     trace.Value.TraceEvent(TraceEventType.Information, 2, "Class2 speaking out"); 
    } 
} 

public class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      var listener = new TextWriterTraceListener(@"C:\trace.txt"); 
      Trace.Listeners.Add(listener); 

      var classOne = new Class1(); 
      var classTwo = new Class2(); 
      classOne.DoSomething(); 
      classTwo.DoSomethingElse(); 
     } 
     finally 
     { 
      Trace.Close(); 
     } 
    } 
} 
0

Ich bin gerade auf dieses Problem gestoßen. In meinem Fall habe ich auch Spurenquellen in jeder Klasse erstellt. Die Listener, die in app.config sind, werden zu allen Quellen hinzugefügt, kein Problem, aber es gibt einen bestimmten Listener, den ich zur Laufzeit hinzufügen muss. Dies funktioniert natürlich nur mit der Trace-Quelle, zu der der Listener hinzugefügt wurde. Ich sehe zwei Optionen - eine einzelne Trace-Quelle erstellen und sie an den Rest der App weitergeben (yuck) oder eine einzelne Quelle für statische Traces in einer Hilfsklasse haben, auf die sonst alles verweist. So habe ich:

public class LogHelper { /// /// The trace source logger for the application. /// public static readonly TraceSource Logger = new TraceSource("FruityBlergs", SourceLevels.All); }

Die LogHelper Klasse setzt auch den Hörer und verschiedene andere Filter auf, die zur Laufzeit konfigurieren bekommen. Das hat mir bisher gut getan. Wenn aus irgendeinem Grund eine bestimmte Klasse ein anderes Verhalten benötigt, können Sie dennoch eine Ablaufverfolgungsquelle in dieser Klasse erstellen.

1

Basierend auf this StackOverflow answer und this answer

Hier ist eine Möglichkeit, es zu tun:

private static void AttachToAllTraceSources(TraceListener yourListener) 
    { 
     TraceSource ts = new TraceSource("foo"); 
     List<WeakReference> list = (List<WeakReference>)GetInstanceField(typeof(TraceSource), ts, "tracesources"); 
     foreach(var weakReference in list) 
     { 
      if(weakReference.IsAlive) 
      { 
       TraceSource source = (weakReference.Target as TraceSource); 
       if(source != null && source.Name != "foo") 
       { 
        source.Listeners.Add(yourListener); 
       } 
      } 
     } 
    } 
+0

Dieses nur Trace bekommt die instanziiert wurden. Wenn es eine Möglichkeit gäbe, dies zu einer beobachtbaren Sammlung zu machen, würden wir mit Gas kochen. – BozoJoe