Tracing and Exception Catching using Trace Listeners

The .NET framework ships with a very flexible tracing feature provided through the Trace class in the System.Diagnostics namespace.

    Debug.Diagnostics.Trace.WriteLine(“My Debug Output”);

Whenever you need to write some debug output just use Trace.WriteLine to send the debug output to a Trace Listener. In my project I have added some line of code to the global.asax.cs file to ensure that any unhandled exception gets written out:

    protected void Application_Error(Object sender, EventArgs e)
    {
        Exception exc = Server.GetLastError();
        if (exc.InnerException != null)
        {
            System.Diagnostics.Trace.WriteLine(exc.InnerException.Message);
            System.Diagnostics.Trace.WriteLine(exc.InnerException.StackTrace);
            System.Diagnostics.Trace.Flush();
        }
    }

The trace output can be consumed by a Trace Listener. This can either be one of the Trace Listeners shipped with the .NET framework (DefaultTraceListener, TextWriterTraceListener or EventLogTraceListener) or a custom Trace Listener.

The easiest way to add a trace listener to your web application is to add it to the web.config.

    <system.diagnostics>
        <trace autoflush=”true” indentsize=”4″>
            <listeners>
                <add name=”LogFileListener” type=”System.Diagnostics.TextWriterTraceListeners” initializeData=”c:\MyTrace.txt” />
                <remove type=”System.Diagnostics.DefaultTraceListener” />
            </listeners>
        </trace>
    </system.diagnostics>

In the sample above I showed how to add the TextWriterTraceListener and how to remove the DefaultTraceListener from the application.

The DefaultTraceListener is a little bit inconvenient for monitoring a system as it requires to have either a debugger attached to the process or a listener running that gathers the trace output on the fly. The EventLogTraceListener on the other hand is a very interesting one as it allows to log event log entries – so you are easily able to identify when the output was written. The TextWriterTraceListener seems to be the solution for this but it has one caveat: it does not log the date and time when the output has been written.

As the long term solution for my project requires that the output will be written to a database I decided to create a custom Trace Listener from scratch that works similar to the TextWriterTraceListener but also includes the Current Date and Time in the output. Here is the source code of this listener:

    using System;
    using System.Diagnostics;
    using System.IO;

    namespace StefanG.TraceListeners
    {
        public class SLGTestTraceListener : TraceListener 
        {
            TextWriter writer;

            public SLGTestTraceListener(string fileName) 
            {
                TextWriter writer = new StreamWriter(fileName, true);
                if (writer == null) throw new ArgumentNullException(“writer”);
                this.writer = writer;
            }
       
            public override void Close() 
            {
                if (writer != null) 
                writer.Close();
            }

            protected override void Dispose(bool disposing) 
            {
                if (disposing) 
                this.Close();
            }               

            public override void Flush() 
            {
                if (writer == null) return;
                writer.Flush();
            }

            public override void Write(string message) 
            {
                if (writer == null) return;   
                if (NeedIndent) 
                {
                    writer.Write(DateTime.Now+” – “);
                    WriteIndent();
                }
                writer.Write(message);
            }

            public override void WriteLine(string message) 
            {
                if (writer == null) return;   
                if (NeedIndent) 
                {
                    writer.Write(DateTime.Now+” – “);
                    WriteIndent();
                }
                writer.WriteLine(message);
                NeedIndent = true;
            }
        }
    }

To add this listener to your web.config Just replace the type attribute in the add line of the web.config with the namespace and module name. E.g. if your DLL is named MyTraceListener the add line would look like this:

   <add name=”LogFileListener” type=”StefanG.TraceListeners.SLGTestTraceListener” initializeData=”c:\MyTrace.txt” />

Now every unhandled exception raised in your web application will automatically be logged in the MyTrace.txt log file including date and time.

8 Comments


  1. Nice piece of code Stefan but we should better use 3rd party logging application (log4j or entreprise logging application) that provide tons of features : level of logging, multiple listeners and so on.

    Reply

  2. Is this features available in both .net 1.1 and 2.0. I have tried this in my 2.0 application and it is not working as expected.

    Reply

  3. Hi Murugan,

    afaik these basic concepts of ASP.NET haven’t changed.

    Cheers,

    Stefan

    Reply

  4. Thanks Stefan,

    I just followed what you mentioned here, but it is not working for me (in asp.net 1.1). I am getting an Configuratio error with "Parser Error Message: Exception in configuration section handler." at first time, for further request the error is not comming and the file also not created.

    Murugan G

    Reply

  5. Sounds like an error in your web.config.

    Reply

  6. I have copied the system.diagnostics element verbatim from my 2.0 web app to a 1.1 web app.  Here is the XML element:

    <system.diagnostics>

    <trace autoflush="true">

    <listeners>

    <add

    name="TraceLog"

    type="System.Diagnostics.TextWriterTraceListener"

    initializeData="Timer.log"

    />

    </listeners>

    </trace>

    <switches>

    <add name="TimerLogging" value="4"/>

    </switches>

    </system.diagnostics>

    Do you see an error in this?  I didn’t think so.  So what gives?  I knew this didn’t work in 1.0, but I thought it was fixed in 1.1.  FWIW, I am running this on my developer box, which is running WinXP SP2.

    BTW, Stefan, I was an EE in the MS Charlotte office from December 1997 – April 2000.  It was a fun group to be in…but now that I’m designing and coding apps full-time, I’m more satisfied with my work.

    Reply

  7. BTW, with regard to that last comment…

    the system.diagnostics element is the child of the configuration element, as specified in the NetFx 1.1 documentation.  As I mentioned, it works fine in 2.0…

    Chris Falter

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.