Добавить/удалить TraceListener во все TraceSources
Я ищу способ добавления и удаления TraceListener для всех существующих TraceSources.
(Я не уверен, что мой подход здесь правильный, какие другие способы я могу использовать?
В основном я хочу записать весь вывод трассировки в файл, который использует текущее имя проекта как имя файла. Всякий раз, когда пользователь создает или возобновляет проект, я хочу добавить журналы в правильный файл. Одновременно может быть открыт только один проект.)
Пример кода:
Я создаю несколько TraceSources в моем приложении, по одному для каждого класса
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");
}
Теперь я хочу добавить или удалить traceListener во все мои трассировки в Runtime, например:
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
}
До сих пор я не нашел способа сделать это, не открыв все мои трассировочные источники (кажется плохая идея), а затем перечисляю все мои классы следующим образом:
Class1.Trace.Add( myListener );
Class2.Trace.Add( myListener );
...
который кажется плохим выбором дизайна на нескольких уровнях.
или
Добавьте все мои TraceSources в пользовательскую глобальную коллекцию в конструкторе каждого класса (легко забыть/испортить, а глобальные переменные - плохие)
Есть ли лучший способ? В принципе, я ищу способ установить другой приемник по умолчанию
Ответы
Ответ 1
Основываясь на fooobar.com/questions/5850/... и этот ответ
Вот один из способов сделать это:
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);
}
}
}
}
Ответ 2
В .NET 4 и выше вы можете использовать Lazy < > для ленивой загрузки ваших TraceSources после настройки слушателей. См. Следующую рабочую примерную программу:
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();
}
}
}
Ответ 3
Я сам столкнулся с этой проблемой. В моем случае у меня также есть источники трассировки, созданные в каждом классе. Слушатели, которые находятся в app.config, не добавляются ко всем источникам без проблем, но есть некоторый слушатель, который мне нужно добавить во время выполнения. Это, конечно, работает только с источником трассировки, к которому добавляется слушатель. Я вижу два варианта: создайте один источник трассировки и передайте его всем остальным приложениям (yuck) или используйте один статический источник трассировки в вспомогательном классе, который ссылается на все остальные. Поэтому у меня есть:
public class LogHelper
{
///
/// The trace source logger for the application.
///
public static readonly TraceSource Logger = new TraceSource("FruityBlergs", SourceLevels.All);
}
Класс LogHelper также устанавливает слушателя и различные другие фильтры, которые настраиваются во время выполнения. До сих пор это работало хорошо. Если по какой-то причине конкретный класс нуждается в другом поведении, вы все равно можете создать источник трассировки в этом классе.