C#如何在运行时启用/禁用网络跟踪?

4

在我找到的示例中,跟踪是通过配置文件启用的,例如

    <?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <system.diagnostics>
    <sources>
      <source name="System.Net" tracemode="includehex" maxdatasize="1024">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="System.Net" value="Verbose"/>
    </switches>
    <sharedListeners>
      <add name="System.Net"
        type="System.Diagnostics.TextWriterTraceListener"
        initializeData="network.log"
      />
    </sharedListeners>
    <trace autoflush="true" indentsize="4" />    
  </system.diagnostics>
</configuration>

但是我不希望配置文件随我的dll一起发布。此外,我需要能够在代码中“即时”启用/禁用跟踪并更改日志名称。

FileStream stream = new FileStream("D:\\network1.log", FileMode.OpenOrCreate);
TextWriterTraceListener listener = new TextWriterTraceListener(stream);
Trace.Listeners.Add(listener);
Trace.AutoFlush = true;

TraceSwitch ts = new TraceSwitch("System.Net", ".Net");
ts.Level = TraceLevel.Verbose;

这段代码没有记录任何内容,我不知道在哪里添加开关,也不确定是否正确。尽管监听器能够工作,但它无法获取任何数据。

我一直在阅读 MSDN 和这篇博客文章 http://www.codeguru.com/csharp/.net/article.php/c19405/Tracing-in-NET-and-Implementing-Your-Own-Trace-Listeners.htm。从我的理解来看,一旦添加到 Trace.Listeners 中,监听器应该记录当前 exe 中的所有跟踪信息,但显然情况并非如此。

那么怎么才能实现呢?

编辑:我已经通过反汇编 TextWriterTraceListener 并使用反汇编的代码实现了自己的 TraceListener,在 Write 和 WriteLine 方法中添加了 if 语句来检查另一个类的某些静态字段,并将我的类型添加到配置中,以绕过这种限制。

2个回答

7
您无法通过代码启用System.Net的跟踪,至少不是以支持的方式。
首先,让我指出您混淆了TraceSwitchTraceSourceTraceSource用于跟踪消息。 TraceSwitch只控制记录哪些内容。
当您实例化TraceSource时,它通过检查系统诊断设置的<sources>集合中是否有与其同名的<source>来初始化自身。如果找到,则使用提供的设置来构建该实例。然后,您的程序将通过调用TraceEvent或其他任何方法来使用该特定的TraceSource实例记录其数据。
如果没有找到配置,则使用SwitchLevel设置为关闭状态的DefaultTraceListener配置TraceSource
上面描述的内容也是内部的System.Net.Logging类在其InitializeLogging方法中执行的操作。它创建自己的一个System.NetTraceSource实例,一旦创建,要么按照配置文件中定义的配置,要么按照默认值进行配置。所有在System.Net命名空间中的类所做的日志记录都使用这个私有/内部TraceSource
没有公共接口可以让您插入或拦截TraceSource的构造函数,因此您无法控制要连接哪个监听器或在共享/单例(如TraceSource)上设置开关级别。也没有选项可以获取内部System.Diagnostics.DiagnosticsConfiguration类实例。
我尝试过System.Configuration.Internal,但最终放弃了它。
如果您确实想使用反射,则可以获取内部静态类型System.Net.Logging并从静态属性Web中获取对TraceSource的引用。一旦获取到引用,您可以设置监听器和开关级别。这是一个内部实现细节,可能会在不通知的情况下更改,因此我不建议这样做。
要控制日志记录,请为System.Net中的类创建重载,并添加自己的TraceSource实例,并将信息记录到该实例中。

0
对于使用.NET Core及更高版本的读者,您可以通过创建一个继承自System.Diagnostics.Tracing.EventListener的类来实现这一点。
有关详细信息和原始建议,请参见https://github.com/dotnet/runtime/issues/64977
示例:
private class SystemNetEventListener : EventListener
{
  protected override void OnEventSourceCreated(EventSource eventSource)
  {
    // take anything from System.Net
    if (eventSource.Name?.StartsWith("Private.InternalDiagnostics.System.Net.") == true)
    {
      EnableEvents(eventSource, EventLevel.LogAlways);
    }
  }

  protected override void OnEventWritten(EventWrittenEventArgs eventData)
  {
    try
    {
      // produce a string that can be logged
      var sb = new StringBuilder().Append($"{eventData.TimeStamp:HH:mm:ss.fffffff}[{eventData.EventName}] ");
      for (int i = 0; i < eventData.Payload?.Count; i++)
      {
        if (i > 0)
          sb.Append(", ");
        sb.Append(eventData.PayloadNames?[i]).Append(": ").Append(eventData.Payload[i]);
      }

      Console.WriteLine(sb.ToString().Trim());
    }
    catch
    {
      // on failure... well... we are the logger, so there's nobody to tell we failed
    }
  }
}

使用方法:

var listener = new SystemNetEventListener(); // start logging
... // do HTTP/Websocket stuff
listener.Dispose(); // stop logging

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接