【问题标题】:Turning tracing off via app.config通过 app.config 关闭跟踪
【发布时间】:2011-05-07 20:40:17
【问题描述】:

我正在尝试使用 System.Diagnostics 进行一些非常基本的日志记录。我想我会使用盒子里的东西,而不是像 Log4Net 或 EntLib 这样的额外依赖。

我已经准备好了,追踪工作非常顺利。代码sn-p:

Trace.TraceInformation("Hello World")

App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <trace autoflush="true" indentsize="4">
      <listeners>
        <add name="TraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="Trace.log" traceOutputOptions="DateTime" />
        <remove name="Default" />
      </listeners>
    </trace>
  </system.diagnostics>
</configuration>

我的小“Hello World”很好地显示在我的 Trace.log 文件中。但现在我想关闭跟踪,所以我深入研究 MSDN 并找到 How to: Configure Trace Switches 。我添加了 &lt;switches&gt; 元素,现在我的 app.config 看起来像这样:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <trace autoflush="true" indentsize="4">
      <listeners>
        <add name="TraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="Trace.log" traceOutputOptions="DateTime" />
        <remove name="Default" />
      </listeners>
    </trace>
    <switches>
      <add name="Data" value="0" />
    </switches>
  </system.diagnostics>
</configuration>

value="0" 应该关闭跟踪 - 至少如果您随后关注 How to: Create and Initialize Trace Switches,它会告诉您添加这行代码:

Dim dataSwitch As New BooleanSwitch("Data", "DataAccess module")

这对我来说没有意义:我只需要声明一个 BooleanSwicth 的实例就可以通过 .config 文件管理(禁用)跟踪?我应该喜欢……使用……某处的对象吗?

无论如何,我确定我在某处遗漏了一些非常明显的东西。请帮忙。

如何在 app.config 中关闭跟踪?

【问题讨论】:

    标签: c# .net vb.net configuration trace


    【解决方案1】:

    我同意@Alex Humphrey 的建议,即尝试使用 TraceSources。使用 TraceSources,您可以更好地控制日志记录/跟踪语句的执行方式。例如,你可以有这样的代码:

    public class MyClass1
    {
      private static readonly TraceSource ts = new TraceSource("MyClass1");
    
      public DoSomething(int x)
      {
        ts.TraceEvent(TraceEventType.Information, "In DoSomething.  x = {0}", x);
      }
    }
    
    public class MyClass2
    {
      private static readonly TraceSource ts = new TraceSource("MyClass2");
    
      public DoSomething(int x)
      {
        ts.TraceEvent(TraceEventType.Information, "In DoSomething.  x = {0}", x);
      }
    }
    

    TraceSource.TraceEvent 调用将根据关联 Switch 的配置级别自动检查消息的级别 (TraceEventType.Information),并确定是否应实际写出消息。

    通过为每种类型使用不同名称的 TraceSource,您可以单独控制这些类的日志记录。您可以启用 MyClass1 日志记录,也可以禁用它,或者您可以启用它但仅在消息级别 (TraceEventType) 大于某个值时才记录(可能只记录“警告”或更高)。同时,您可以打开或关闭 MyClass2 的登录或设置到一个级别,完全独立于 MyClass1。所有这些启用/禁用/级别的东西都发生在 app.config 文件中。

    使用 app.config 文件,您还可以以相同的方式控制所有 TraceSource(或 TraceSource 组)。因此,您可以配置 MyClass1 和 MyClass2 都由同一个 Switch 控制。

    如果您不想为每种类型使用不同名称的 TraceSource,您可以在每个类中创建相同的 TraceSource:

    public class MyClass1
    {
      private static readonly TraceSource ts = new TraceSource("MyApplication");
    
      public DoSomething(int x)
      {
        ts.TraceEvent(TraceEventType.Information, "In DoSomething.  x = {0}", x);
      }
    }
    
    public class MyClass2
    {
      private static readonly TraceSource ts = new TraceSource("MyApplication");
    
      public DoSomething(int x)
      {
        ts.TraceEvent(TraceEventType.Information, "In DoSomething.  x = {0}", x);
      }
    }
    

    这样,您可以使应用程序中的所有日志记录发生在同一级别(或关闭或使用相同的 TraceListener,或其他)。

    您还可以将应用程序的不同部分配置为可独立配置,而不必为每种类型定义唯一的 TraceSource 带来“麻烦”:

    public class Analysis1
    {
      private static readonly TraceSource ts = new TraceSource("MyApplication.Analysis");
    
      public DoSomething(int x)
      {
        ts.TraceEvent(TraceEventType.Information, "In DoSomething.  x = {0}", x);
      }
    }
    
    public class Analysis2
    {
      private static readonly TraceSource ts = new TraceSource("MyApplication.Analysis");
    
      public DoSomething(int x)
      {
        ts.TraceEvent(TraceEventType.Information, "In DoSomething.  x = {0}", x);
      }
    }
    
    public class DataAccess1
    {
      private static readonly TraceSource ts = new TraceSource("MyApplication.DataAccess");
    
      public DoSomething(int x)
      {
        ts.TraceEvent(TraceEventType.Information, "In DoSomething.  x = {0}", x);
      }
    }
    
    public class DataAccess2
    {
      private static readonly TraceSource ts = new TraceSource("MyApplication.DataAccess");
    
      public DoSomething(int x)
      {
        ts.TraceEvent(TraceEventType.Information, "In DoSomething.  x = {0}", x);
      }
    }
    

    通过以这种方式检测您的类,您可以将应用日志的“数据访问”部分设置在一个级别,而将应用的“分析”部分记录在不同的级别(当然,您的应用中的一个或两个部分)可以配置为禁用日志记录)。

    这是配置 TraceSources 和 TraceSwitches 的 app.config 文件的一部分:

    <system.diagnostics>
      <trace autoflush="true"></trace>
      <sources>
        <source name="MyClass1" switchName="switch1">
          <listeners>
            <remove name="Default"></remove>
            <add name="console"></add>
          </listeners>
        </source>
        <source name="MyClass2" switchName="switch2">
          <listeners>
            <remove name="Default"></remove>
            <add name="console"></add>
          </listeners>
        </source>
      </sources>
      <switches>
        <add name="switch1" value="Information"/>
        <add name="switch2" value="Warning"/>
      </switches>
      <sharedListeners>
        <add name="console"
             type="System.Diagnostics.ConsoleTraceListener">
        </add>
        <add name="file"
             type="System.Diagnostics.TextWriterTraceListener"
             initializeData="trace.txt">
        </add>
      </sharedListeners>
    </system.diagnostics>
    

    如您所见,您可以配置单个 TraceSource 和单个 Switch,并且所有日志记录都将通过单个控制级别进行(即您可以关闭所有日志记录或使其在某个级别记录)。

    或者,您可以定义多个 TraceSource(并在您的代码中引用相应的 TraceSource)和多个 Switch。 Switch 可以共享(即多个 TraceSource 可以使用同一个 Switch)。

    最终,现在通过付出更多努力来使用 TraceSources 并在您的代码中引用适当命名的 TraceSources(即在逻辑上定义 TraceSource 名称,以便您可以对应用程序中的日志进行所需程度的控制),您从长远来看,将获得显着的灵活性。

    这里有一些链接可能会在您继续使用 System.Diagnostics 时为您提供帮助:

    .net Diagnostics best practices?

    Logging best practices

    What's the best approach to logging?

    Does the .Net TraceSource/TraceListener framework have something similar to log4net's Formatters?

    在我发布的链接中,经常讨论“最佳”日志框架。我并不是要说服你改变 System.Diagnostics。这些链接也往往包含有关使用 System.Diagnostics 的良好信息,这就是我发布它们的原因。

    我发布的几个链接包含指向Ukadc.Diagnostics 的链接。这是一个非常酷的 System.Diagnostics 库插件,它添加了丰富的格式化功能,类似于您可以使用 log4net 和 NLog 执行的操作。该库对您的应用施加了仅配置依赖,而不是代码或引用依赖。

    【讨论】:

    • 像魅力一样工作。您在示例 .config 文件中缺少一个“”元素。
    • 我添加了一个 来关闭 节点。
    • 为什么我不能把这 5 次?真棒答案!非常感谢!
    【解决方案2】:

    您不会以这种方式关闭全局跟踪。

    你必须
    1) 声明一个开关并设置它的值:

    <switches>
      <add name="MySwitch" value="Information"/>
    </switches>
    

    2) 将此开关与您使用的 TraceSource 关联:

    <sources>
      <source name="MySource" switchName="MySwitch"/>
    </source>
    

    因此,您通过名为“MySource”的 TraceSource 编写的任何内容都会根据开关值进行过滤。

    如果你使用像Trace.Write这样的静态方法,我想你根本不能使用开关,因为没有TraceSource来应用过滤器。
    如果您想通过静态方法关闭跟踪,只需删除所有侦听器:&lt;listeners&gt; &lt;clear/&gt; &lt;/listeners&gt;

    【讨论】:

      【解决方案3】:

      在需要记录时检查 dataSwitch 的状态,如下所示:

      http://msdn.microsoft.com/en-us/library/aa984285%28v=VS.71%29.aspx

      但是,这非常令人讨厌,不得不将这些支票放在任何地方。他们是您不想简单地从 app.config 中的 listeners 集合中删除 TraceListener 的原因吗?

      除此之外,我将使用包括TraceSource 在内的 .NET 2.0+ 跟踪内容进行调查。 new(er) 的东西提供了更高程度的配置,你可能会发现它更合适。

      http://msdn.microsoft.com/en-us/library/ms228993.aspx

      【讨论】:

        【解决方案4】:

        是源节点的switchValue属性:

        <system.diagnostics>
        <sources>
          <source name="System.ServiceModel"
                  switchValue="Off"
                  propagateActivity="true">
            <listeners>
              <add name="traceListener"
                  type="System.Diagnostics.XmlWriterTraceListener"
                  initializeData= "somePath" />
            </listeners>
          </source>
        </sources>
        <trace autoflush="true" />
        

        【讨论】:

          【解决方案5】:

          稍后加入有关 app.config 的快速脚注,以防万一这可以节省几天的时间:

          假设您有一个包含 classA 的启动 (.exe) projectA,它使用包含 classB 的 projectB (.dll)。

          ClassB 反过来使用一个新的 TraceSource("classB") 实例。为了配置它,您需要修改 app.config 或 projectA。调整 projectB 的 app.config 不会有任何结果。

          还要注意放置

          <system.diagnostics>
          

          如果将 app.config 中的部分放在该部分之前,似乎会导致问题:

          <configSections>
          

          或在部分之后:

          <userSettings>
          

          至少在我的情况下,当我尝试将其放置在项目的 app.config 中的这些位置时,我遇到了错误。对我有用的布局是:

          <?xml version="1.0" encoding="utf-8" ?>
          <configuration>
              <configSections>
                   ...config sections here if any...
               </configSections>
               <system.diagnostics>
                   <trace autoflush="true"/>
                   <sources>
                       <source name="classB"
                           switchName="mySwitch"
                           switchType="System.Diagnostics.SourceSwitch" >
                           <listeners>
                              <clear/>
                              <add name="textwriterListener"
                                   type="System.Diagnostics.TextWriterTraceListener"
                                   initializeData="ClassBLog.txt"
                                   traceOutputOptions="DateTime" />
                           </listeners>
                       </source>
                    </sources>
                    <switches>
                       <add name="mySwitch" value="Verbose" />
                    </switches>
               </system.diagnostics>
               <runtime>
                   ...runtime sections here if any...
               </runtime>
               <userSettings>
                   ...usersettings sections here if any...
               </userSettings>
           </configuration>
          

          【讨论】:

            【解决方案6】:

            试试这个简单的解决方案。在下面的示例中,“SomeNoisyLibrary”在日志中乱扔了许多无用的条目。我们用 "when condition"

            过滤它们

            https://github.com/NLog/NLog/wiki/When-Filter

            <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    internalLogFile="../log/MyApplication.log"
                    autoReload="true" throwExceptions="true">
            
              <targets async="true">
                <target xsi:type="File" 
                        name="file"
                        layout="${longdate} | ${level:uppercase=true} | ${logger} | ${message} ${exception:format=ToString}"
                        fileName="../log/MyApplication.${processid}.${shortdate}.log" keepFileOpen="false"
                        maxArchiveFiles="10"
                        archiveAboveSize="10024000"
                        archiveEvery="Day"
                        />
                <target xsi:type="ColoredConsole" 
                        name="console" 
                        layout="${longdate} | ${level:uppercase=true} | ${logger} | ${message}${exception:format=ToString}" />
              </targets>
            
              <rules>
                <logger name="*" minlevel="Info" writeTo="file,console">
                  <filters defaultAction='Log'>
                    <when condition="equals('${logger}','SomeNoisyLibrary')" action="Ignore" />
                  </filters>
                </logger>
              </rules>
            </nlog>
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-02-03
              • 2013-08-18
              • 1970-01-01
              • 2017-02-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多