4

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

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

4

2 回答 2

1
  1. 如果您不想创建自己的 .dll 文件,抑制来自有问题 dll 的消息TraceListener的唯一方法是使用.TraceTraceTrace.Listeners.Clear()

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

  1. 我建议创建一个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.

        }
    }
}
于 2017-05-23T07:41:30.407 回答
0

根据ILSpyTrace.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);
于 2013-10-14T04:34:12.260 回答