How to use TraceListeners in our program

In proactive programming, you need to configure your TraceListeners in your App.Config file or Web.Config file. By default, Microsoft .NET provides several listeners containing DefaultTraceListener, TextWriterTraceListener, EventLogTraceListener, XmlTraceListener , ConsoleTraceListener, and DelimitedListTraceListener. However, we could create our own custom listeners because those listeners from BCL are not sealed. Before we do that, I wanted to talk more about proactive programming.

We mainly use two classes in proactive programming: System.Diagnostics.Debug and System.Diagnostics.Trace. You could open your reflector and find it in System.Diagnostics namespace. You’ll discover that almost all the methods of Trace and Debug class finally call TraceIntelnal’s methods which will retrieve listeners there. I introduce this, because you now understand why Debug and Trace could share some listeners.

Now, let’s get started by using the DefaultTraceListener provided by Microsoft .NET Framework. Please create a C# console application and add:

System.Diagnostics.Debug.Assert(1!=1, “1!=1”); // (C# version)
in Main function. Build the project and then press F5 to start debugging, you’ll receive a dialogbox like below:

assert.png

 

At the mean time, the assert message was displayed in Output window in Visual Studio:
==========================================================

---- DEBUG ASSERTION FAILED ----

---- Assert Short Message ----

1!=1

---- Assert Long Message ----

at Program.Main(String[] args) C:\Projects\Debug\ConsoleApplication1\Program.cs(12)

at AppDomain._nExecuteAssembly(Assembly assembly, String[] args)

at AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)

at HostProc.RunUsersAssembly()

========================================================

Usually, developers wanted to disable the alert box and store the output information in a separate log file. To achieve that, you need to use TextWriterTraceListener and configure it in App.Config file like below:

   1: <system.diagnostics> 
  2:        <assert assertuienabled="false" logfilename="TraceLog.txt"/>
  3:        <listeners>
  4:         <remove name="Default"/>
  5:         <add initializeData="TraceLog.txt" name="MyListener" type="System.Diagnostics.TextWriterTraceListener, 
/>
  6:         System, 
  7:         Version=2.0.0.0, 
  8:         Culture=neutral,
  9:         PublicKeyToken=b77a5c561934e089"
 10: 
 11:       </listeners>
 12:     </system.diagnostics>
 13: 

Please note here:

   1: type="System.Diagnostics.TextWriterTraceListener, 
  2:       System, 
  3:        Version=2.0.0.0, 
  4:        Culture=neutral,     PublicKeyToken=b77a5c561934e089"/>

The order is: full type name, assembly name, assembly version number, culture and then the PublicKeyToken. Since this listener is already installed in GAC, you need to provide all those information for VS to locate the assembly. If you place your assembly in the Output path of your project, those information is not needed (just full type name and assembly name is OK). I’ll demonstrate that in the following custom TraceListener.

This time, if you press F5 to debug your application, you could find a TraceLog.txt file in your output folder. Most probablely, its content is:

Fail: 1!=1
As you can see, information here does not contain all the details but only a fail note. How to make it write all the details to this log file? One solution is to create a custom TextTraceListener and let it do works we want.

To implement a custom TraceListener, you could create a Class Library project and add a CustomTraceListener class which is inherited from TraceListener class. For example:

   1: 
  2:             Writer.WriteLine("Debug assert failed");
  3:             Writer.WriteLine("The message is:");
  4:             if (null != message)
  5:             {
  6:                 Writer.WriteLine(message);
  7:             }
  8:             Writer.WriteLine("The detail message is:");
  9:             if (null != detailMessage)
 10:             {
 11:                 Writer.WriteLine(detailMessage);
 12:             }
 13:  
 14:             // There's four levels of stack between here and the user's code.
 15:             StackTrace st = new StackTrace(3, true);
 16:             Writer.WriteLine(st.ToString());
 17:         }
 18:         #endregion
 19:     }
 20: }

Build the project and copy the dll file to the output of your test application. Make your App.Config have the following section:

   1:  <system.diagnostics>
  2:     <trace autoflush="true" indentsize="0">
  3:       <listeners>
  4:         <add name="CustomTraceListener" initializeData="TraceLog.log" 
  5:              type="CustomTraceListenerSample.CustomTraceListener, CustomTraceListenerSample"/>
  6:       </listeners>
  7:     </trace>
  8:   </system.diagnostics>

All the information that Debug and Trace detected will be written to TraceLog.log file. Well, happy proactive programming!​