抑制来自特定 DLL 的跟踪消息

Posted

技术标签:

【中文标题】抑制来自特定 DLL 的跟踪消息【英文标题】:Suppress Trace Messages From Specific DLL 【发布时间】:2013-10-14 04:16:28 【问题描述】:

我正在使用第 3 方库,它多次调用该函数:

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 过滤器?

【问题讨论】:

只是想知道,你为什么不想自己制作TraceListener @jrh 如果我没记错的话,我试图摆脱 Visual Studio 输出窗口中的所有这些额外消息,以便调试其他问题,例如绑定问题。此外,在我使用的库的未来版本中,作者删除了他们的 Trace.WriteLine 调用 在这种情况下,我想我知道一个简单的解决方案,我会在一周左右回来后发布答案。不过,您在自己的代码中使用了 Trace.WriteLine,对吧?意思是,你不只是想禁止所有 Trace.WriteLine 消息,只是来自一个 dll 的消息。 我使用了一个第三方库,它的源代码中有 Trace.WriteLine 调用(并且不想分支/重新编译它)。我想抑制来自一个特定编译 dll 的 Trace.WriteLine 消息。 【参考方案1】:
    如果您不想创建自己的TraceListener,抑制来自有问题的dll 的Trace 消息的唯一方法是使用Trace.Listeners.Clear() 停止所有Trace 消息。

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

    我建议创建一个TraceListener,它使用反射在调用堆栈中查找要忽略的 dll。

无法覆盖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.

        
    

【讨论】:

如果有人感兴趣,here's some test code in a gist that shows the source behind NoisyLibrary。 -- gist 上的 .cs 语法高亮显示效果似乎不太好,所以我将其设置为 cpp。【参考方案2】:

根据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 以表明它不打算被直接调用,例如:

protected abstract void WriteLine(string message);

【讨论】:

我认为这解释了设计。如果第 3 方库调用 Trace.WriteLine(string message),有没有办法过滤和抑制这些消息? 似乎无路可走

以上是关于抑制来自特定 DLL 的跟踪消息的主要内容,如果未能解决你的问题,请参考以下文章

抑制来自 sqlplus 输出的 CURSOR 消息

在 UI 抑制模式下向对话 Lync 2013 SDK 中的特定用户发送 IM 消息

调用 Set-ExecutionPolicy 时如何抑制来自脚本的警告消息

运行单元测试时如何抑制来自 node.js 应用程序的应用程序日志消息?

在 syslog-ng 中抑制重复消息到 SQL 目标

跟踪来自网络检查员的服务器推送消息