A dive into the TraceListener class

I had a quick dive into the TraceListener class today. I want to use Assert() in the System.Diagnostics.Trace class from an ASP.NET application, and wondered how to configure the output to file, event log and mail. Making the Assert is easy:

Trace.Assert(errors = 0, "Assert happened!", "A detailed message for you guys!")

Now, to write that to a file, just add to web.config:

<system.diagnostics>
  <trace autoflush="false" indentsize="4"/>
  <assert assertuienabled="false" logfilename="c:\AssertLog.txt"/>
</system.diagnostics>

When an assertion fails, this is written to the file:

---- DEBUG ASSERTION FAILED ----
---- Assert Short Message ----
Assert happened!
---- Assert Long Message ----
A detailed message for you guys!

    at AssertForm.btnOk_Click(Object sender, EventArgs e)  c:\inetpub\wwwroot\AssertTest\AssertForm.aspx.vb(30)
    at Button.OnClick(EventArgs e) 
    at Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) 
    at Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) 
    at Page.RaisePostBackEvent(NameValueCollection postData) 
    at Page.ProcessRequestMain() 
    at Page.ProcessRequest() 
    at Page.ProcessRequest(HttpContext context) 
    at CallHandlerExecutionStep.System.Web.HttpApplication+IExecutionStep.Execute() 
    at HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 
    at HttpApplication.ResumeSteps(Exception error) 
    at HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) 
    at HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) 
    at HttpRuntime.ProcessRequest(HttpWorkerRequest wr) 
    at ISAPIRuntime.ProcessRequest(IntPtr ecb, Int32 iWRType) 

Now, if you want to write to the Event log, you need to add a listener to the system.diagnostics/trace/listeners section in the web.config. Note that this can also be made through coding:

<system.diagnostics>
  <trace autoflush="false" indentsize="4">
    <listeners>
      <add name="MyEventListener" type="System.Diagnostics.EventLogTraceListener" initializeData="Johan1"/>
      <!-- if you don't want to write to a file, uncomment this, or remove the assert section below
      <remove name="Default" />
      --
>
    </listeners> 
  </trace>
  <assert assertuienabled="false" logfilename="c:\AssertLog.txt"/>
</system.diagnostics>

The "initializeData" specifies the source of the Event log to write to. Note that the event source must exist first. The following message is written to the Event log:

Fail: Assert happened! A detailed message for you guys!

Pity the stack trace isn't written there too, as it is in the log file. You'd have to write your own TraceListener for that, which is what I did to send the trace message in a mail. To do that, inherit from TraceListener and implement a few lines of code. This is a quick and dirty VB sample that I will rewrite and refactor into c# later:

Imports System.Diagnostics
Imports System.Web.Mail

Public Class SmtpTraceListener
  
Inherits TraceListener

Private _recipient As String
Private _sender As String = "some application"
Private _smtpserver As String = "127.0.0.1"

Public Sub New()
 
MyBase.New()
 
Throw New ApplicationException("SmtpTraceListener must have 'initializeData' attribute specified in config file: recipient,sender,smtpserver")
End Sub

Public Sub New(ByVal smtpData As String)
 
MyBase.New()
 
Dim arrSmtpData() As String

  'TODO: Change this into a more decent string, like "sender=asdas;recipient=asdas,smtpserver=asdas"
  arrSmtpData = smtpData.Split(","c)
  If arrSmtpData.Length > 0 Then
   
_recipient = arrSmtpData(0)
 
End If

  If arrSmtpData.Length > 1 Then
   
_sender = arrSmtpData(1)
 
End If

  If arrSmtpData.Length > 2 Then
   
_smtpserver = arrSmtpData(2)
  End If

End Sub

Private Sub send(ByVal subject As String, ByVal message As String)
  SmtpMail.SmtpServer = _smtpserver
  SmtpMail.Send(_sender, _recipient, subject, message)
End Sub

Public Overloads Overrides Sub Write(ByVal message As String)
  send(
"application message", message)
End Sub

Public Overloads Overrides Sub WriteLine(ByVal message As String)
  Write(message)
End Sub

Public Overloads Overrides Sub Fail(ByVal message As String, ByVal detailMessage As String)
  send(message, detailMessage)
End Sub

End Class

Note that a stuck smtp-data in the "initializeData" attribute, that's the way the DiagnosticsConfigurationHandler reads the config section and initalize the listener constructor. A cooler way to do this is to add your own config-section, which I will do later on I think.

Now, just add the listener to the web.config file:

<add name="MySmtpListener" type="AssertTest.SmtpTraceListener, AssertTest"

initializeData="recipient@company.com,sender@company.com,smtp.company.com"/>

I guess there will be better TraceListeners in Whidbey and Longhorn, but I haven't got my hands on those bits yet.

No Comments