禁止显示来自特定 DLL 的跟踪消息

本文关键字:跟踪 消息 DLL 禁止显示 | 更新日期: 2023-09-27 18:35:24

我正在使用一个第三方库,它对该函数进行了多次调用:

Trace.WriteLine(string message);

这会使Visual Studio输出窗口变得混乱,并使调试我的应用程序变得困难(例如;XAML 绑定警告)。

我正在尝试找到一种方法来阻止来自特定 dll 的所有跟踪消息转储到 Visual Studio 输出窗口 - 编写我自己的 TraceListener 是唯一的前进道路吗?


我无法使TraceFilter/EventTypeFilter适用于没有类别的字符串消息 - 尽管我找不到支持这一点的文档 - 经验上:

TraceFilter.ShouldTrace(...)

由以下函数(不是完整的集合)调用:

Trace.WriteLine(string message, string category);
Trace.TraceError(string message);
Trace.WriteLine(object o);

但未被以下人员调用:

Trace.WriteLine(string message);

有谁知道为什么这个调用避免了ShouldTrace过滤器?

禁止显示来自特定 DLL 的跟踪消息

  1. 如果您不想创建自己的TraceListener,则禁止来自有问题的 dll 的Trace消息的唯一方法是使用 Trace.Listeners.Clear() 停止所有Trace消息。

请注意,这也将停止您自己的Trace调用。我之所以提到这一点,是因为我知道一些应用程序从未使用过Trace.WriteLine并且由于不断写入输出窗口的非常嘈杂的库而受到严重的性能影响。

  1. 我建议创建一个使用反射在调用堆栈中查找要忽略的 dll 的TraceListener
无法

覆盖Trace.WriteLine,但可以在默认TraceListener中覆盖某些调用以达到相同的效果。

使用如下所示的TraceListener可以帮助您清理 Visual Studio 中的输出窗口,以便您可以专注于您感兴趣的事件,而不是受到来自第三方库的消息的轰炸。

请参阅下面的示例代码:

using System;
using System.Diagnostics;
using System.Reflection;
// The library that calls Trace, causing the messages you want to suppress.
using NoisyLibrary;
namespace TraceSuppress
{
    /// <summary>
    /// Trace listener that ignores trace messages from a specific assembly.
    /// </summary>
    public class AssemblyFilteredListener : DefaultTraceListener
    {
        private Assembly assemblyToIgnore;
        public AssemblyFilteredListener(Assembly assemblyToIgnoreTracesFrom)
        {
            this.assemblyToIgnore = assemblyToIgnoreTracesFrom;
        }
        public bool TraceIsFromAssemblyToIgnore()
        {
            StackTrace traceCallStack = new StackTrace();
            StackFrame[] traceStackFrames = traceCallStack.GetFrames();
            // Look for the assembly to ignore in the call stack.
            //
            // This may be rather slow for very large call stacks. If you find that this is a bottleneck
            // there are optimizations available.
            foreach (StackFrame traceStackFrame in traceStackFrames)
            {
                MethodBase callStackMethod = traceStackFrame.GetMethod();
                bool methodIsFromAssemblyToIgnore = (callStackMethod.Module.Assembly == this.assemblyToIgnore);
                if (methodIsFromAssemblyToIgnore)
                {
                    return true;
                }
            }
            // The assembly to ignore was not found in the call stack.
            return false;         
        }

        public override void WriteLine(string message)
        {
            if (!this.TraceIsFromAssemblyToIgnore())
            {
                base.WriteLine(message);
            }
        }         
        public override void Write(string message)
        {
            if (!this.TraceIsFromAssemblyToIgnore())
            {
                base.Write(message);
            }
        }
    }
    class Program
    {
        static void SetupListeners()
        {
            // Clear out the default trace listener
            Trace.Listeners.Clear();
            // Grab the asssembly of the library, using any class from the library.
            Assembly assemblyToIgnore = typeof(NoisyLibrary.LibraryClass).Assembly;
            // Create a TraceListener that will ignore trace messages from that library
            TraceListener thisApplicationOnlyListener = new AssemblyFilteredListener(assemblyToIgnore);
            Trace.Listeners.Add(thisApplicationOnlyListener);
            // Now the custom trace listener is the only listener in Trace.Listeners.
        }
        static void Main(string[] args)
        {
            SetupListeners();            
            // Testing
            //-------------------------------------------------------------------------
            // This still shows up in the output window in VS...
            Trace.WriteLine("This is a trace from the application, we want to see this.");
            // ...but the library function that calls trace no longer shows up.
            LibraryClass.MethodThatCallsTrace();
            // Now check the output window, the trace calls from that library will not be present.
        }
    }
}

根据 ILSpy,Trace.WriteLine(string message)被声明为抽象的,需要被派生类覆盖:

public abstract void WriteLine(string message);

您提到的所有其他方法都会检查ShouldTrace并最终调用Trace.WriteLine(string message)消息。

例如:

public virtual void WriteLine(string message, string category)
{
    if (Filter != null && 
        !Filter.ShouldTrace(null, "", TraceEventType.Verbose, 0, message))
    {
        return;
    }
    if (category == null)
    {
        WriteLine(message);
        return;
    }
    WriteLine(category + ": " + ((message == null) ? string.Empty : message));
}

所以在我看来,真正的原因是Trace类设计师的决定。

他本可以保护该Trace.WriteLine(string message),以表明它不打算直接调用,例如:

protected abstract void WriteLine(string message);