c#中的跟踪2
一个软件总是在自己认为没有bug存在了的情况下发布的。而事实上现实的环境是很复杂的,写好的软件在一个系统上运行良好,可能到另一个系统上运行就会出问题了。这个时候我们需要了解是哪里出现了问题,这样才能着手去改动代码,但是如果在这个时候要用源代码在出问题的机器上调试来确定问题的所在,显得不太现实了,而且这样也容易造成源代码的泄露。解决这个问题的方法是在软件的发布版本中写入一些跟踪选项,以查看正在运行的应用程序的消息。.NET在运行的应用程序中获得一些实时信息是通过命名空间System.Diagnostics中实现的。
在.NET 1.0中,跟踪是通过Trace类和Debug类来实现的,在.NET2.0中引入了新类TraceSource类。TraceSource类对原来的Trace类的实现功能做了一个框架,而且里面的类成员和方法也都不再是静态的了,所以在TraceSource类中就存在了构造方法,我们可以定义多个源。当然这样,带来的是使用上更加复杂。个人感觉TraceSource类用在大型系统中可能更合适一点,如果只是一个小的系统根本没必要用这个类,Trace类的功能足以实现所有的功能了。相比之下,Trace类的Switch功能显得稍微弱了一些,不过通过WriteLineIf方法和TraceSwitch类也可以完成Switch的功能,具体的代码如下:
TraceSwitch ts = new TraceSwitch("mySwitch", "in the Config file");
ts.Level = TraceLevel.Verbose;
Trace.WriteLineIf(ts.TraceError, "Error!!!");
Trace.WriteLineIf(ts.TraceWarning, "Warning!!!");
Trace.WriteLineIf(ts.TraceInfo, "Info!!!");
Trace.WriteLineIf(ts.TraceVerbose, "Verbose!!!");
TraceSwitch类可以通过使用跟踪开关来筛选消息,通过Level属性来获取或设置开关级别(TraceLevel枚举类别(Off(0), Error(1), Warning(2), Info(3), Verbose(4)))。通过TraceError, TraceWarning, TraceInfo, TraceVerbose属性来测试开关的级别。改属性也可以通过配置文件来定义。
<configuration>
<system.diagnostics>
<switches>
<add name="mySwitch" value="1" />
</switches>
</system.diagnostics>
</configuration>
另外Trace类中我没有找到关于Filter的实现,可能这个它也是实现不了的。现在我所知道的他们的区别就是这些了。Trace类的其他用法可以参见另一篇文章。
最简单的TraceSource类的使用方法:
TraceSource source1 = new TraceSource("TraceSourceTest");
TextWriterTraceListener listener1 = new TextWriterTraceListener(System.Console.Out);
source1.Listeners.Add(listener1);
source1.Switch = new SourceSwitch("MySwitch", "Verbose");
source1.TraceInformation("Info Message");
source1.TraceEvent(TraceEventType.Verbose, 3, "Verbose message");
source1.TraceEvent(TraceEventType.Error, 1, "Error message");
source1.TraceData(TraceEventType.Information, 2, new int[] { 1, 2, 3 });
source1.Flush();
source1.Close();
TraceSource类中最重要的两个属性是Listeners和Switch。其中Listeners是TraceListenerCollection类别,它包含了TraceListener类的集合。他的作用同Trace类中的Listeners属性,定义跟踪信息输出的位置,比如控制台,日志文件等。TraceListener类中又定义了一Filter类,以过滤调一些跟踪信息。Switch属性是SourceSwitch类型,他定义了输出消息的类别。从这个框架上来说,使用TraceSource类的跟踪信息可以通过Switch以及Filter来整体定制,而Trace类的这些功能只能通过手工实现。
下面分别一一介绍这些类。TraceSource类中除了那两个属性,还提供了一些输出消息的方法。TraceEvent方法定义一个对应信息类别(TraceEventType),信息ID(用于应用程序内部),以及信息的描述。TraceInformation是TraceEvent的简化版本,它相当于TraceEvent中的消息类别为Information,信息ID为0的信息。使用指定的信息类型、信息标识符和跟踪数据(组),将跟踪数据写入Listeners集合中的监听器中。其中TraceEventType枚举类型包含问题级别值:Verbose, Information, Warning, Error, Critical; 操作级别:Start, Stop, Suspend, Resume。
SourceSwitch类中定义了Level属性,它是一个SourceLevels的枚举类型(Off, Critical, Error, Warning, Information, Verbose, ActivityTracing, All),可以通过SwitSetting属性获取改值。且有:
成员名称 |
说明 |
Off |
不允许任何事件通过。 |
Critical |
只允许 Critical 事件通过。 |
Error |
|
Warning |
|
Information |
允许 Critical、Error、Warning 和 Information 事件通过。 |
Verbose |
允许 Critical、Error、Warning、Information 和 Verbose 事件通过。 |
ActivityTracing |
|
All |
允许所有事件通过。 |
TraceSouce类中的Listeners属性和Trace类中的Listeners属性是一样的。TraceListener的子类有:DefaultTraceListener(输出位置为与之相关联的调试器中,为监听器的默认值),EventLogTraceListener(将跟踪信息写入时间日志),TextWriterTraceListener(输出对象可以是文件,TextWriter类,或Stream类, ConsoleTraceListener(控制台), DelimitedListTraceListener(有分隔符的文件), XmlWriterTraceListener(XML文件)都是它的子类),WebPageTraceListener类(ASP.NET中的跟踪类)。TraceListener类中包含了IndentSize和IndentLevel的属性以及Name,TraceOutputOptions属性,TraceOutputOptions属性为TraceOptions枚举类别,定了监听器打印的额外信息。
成员名称 |
说明 |
None |
不写入任何元素。 |
LogicalOperationStack |
写入逻辑操作堆栈,该堆栈由 CorrelationManager..::.LogicalOperationStack 属性的返回值表示。 |
DateTime |
写入日期和时间。 |
Timestamp |
写入时间戳,该时间戳由 GetTimestamp 方法的返回值表示。 |
ProcessId |
写入进程标识,该标识由 Process..::.Id 属性的返回值表示。 |
ThreadId |
写入线程标识,该标识由当前线程的 Thread..::.ManagedThreadId 属性的返回值表示。 |
Callstack |
写入调用堆栈,该堆栈由 Environment..::.StackTrace 属性的返回值表示。 |
其中日志文件(EventLogTraceListener)没有这个选项,因为这样会导致日志文件太大。
TraceListener类中的Filter属性为TraceFilter类别。它可以提供开关为提供的额外筛选层。改类只定义了ShouldTrace方法,以确定跟踪器是否应该跟踪事件。.net3.0中提供了两个TraceFilter类的子类,EventTypeFilter类和SourceFilter类。EventTypeFilter指示侦听器是否应该基于事件类型进行跟踪,改类中定义了SouceLevels枚举类型的属性,指示要跟踪的时间类别。指示侦听器是否应基于跟踪源跟踪消息,改类中定义了包含string类型的跟踪源名的字符串。
简单的例子如下:
namespace TraceSourceTest
{
class TraceSourceTest
{
private TraceSource traceSource = new TraceSource("TraceSourceTest", SourceLevels.All);
}
class Program
{
static void Main(string[] args)
{
TraceSource source1 = new TraceSource("TraceSourceTest");
/*TextWriterTraceListener listener1 = new TextWriterTraceListener(System.Console.Out);
listener1.Filter = new SourceFilter("TraceSourceTest");
source1.Listeners.Add(listener1);
source1.Switch = new SourceSwitch("MySwitch", "Verbose");*/
source1.TraceInformation("Info Message");
source1.TraceEvent(TraceEventType.Verbose, 3, "Verbose message");
source1.TraceEvent(TraceEventType.Error, 1, "Error message");
source1.TraceData(TraceEventType.Information, 2, new int[] { 1, 2, 3 });
source1.Flush();
source1.Close();
}
}
}
要使用的配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
<source name="TraceSourceTest" switchName="MySourceSwitch" switchType="System.Diagnostics.SourceSwitch">
<listeners>
<add name="text" />
<add name="console" />
<add name="delimited" />
<add name="xml" />
</listeners>
</source>
</sources>
<switches>
<add name ="MySourceSwitch" value="Verbose" />
</switches>
<sharedListeners>
<add name ="console" type = "System.Diagnostics.ConsoleTraceListener" />
<add name ="text" type="System.Diagnostics.TextWriterTraceListener" initializeData="output.txt" />
<add name ="delimited" type="System.Diagnostics.DelimitedListTraceListener" initializeData="delimited.txt"
traceOutputOptions="ProcessId, DateTime, Timestamp" >
<filter type="System.Diagnostics.EventTypeFilter" initializeData ="Warning"/>
</add>
<add name ="xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="xml.xml"
traceOutputOptions="ProcessId, DateTime, Timestamp">
<filter type="System.Diagnostics.SourceFilter" initializeData="TraceSourceTest"/>
</add>
</sharedListeners>
</system.diagnostics>
</configuration>