Most Visual Basic programmers are familiar with using Debug.Print to follow their code's execution. The .NET environment introduces Tracing falicities that allows you to send messages to files or the console.
However the console output could be improved by using colors to highlight certain events.
I developed a simple ColorTraceListener that can be used either with the My.Application.Log object or the Trace.TraceXXX methods.
I first thing to do is create a ClassLibrary. It will be called ColorTraceListener. Add a ColorTraceListener.cs File and fill it with the following code:
Imports System
Imports System.Diagnostics
Imports System.Globalization
Imports System.Text
Imports System.Runtime.InteropServices
Public Class ColorTraceListener
Inherits ConsoleTraceListener
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal useErrorStream As Boolean)
MyBase.New(useErrorStream)
End Sub
Friend Function IsEnabled(ByVal opts As TraceOptions) As Boolean
Return ((opts And Me.TraceOutputOptions) <> TraceOptions.None)
End Function
False)> _
Public Overrides Sub TraceData(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal data As Object)
If ((Me.Filter Is Nothing) OrElse Me.Filter.ShouldTrace(eventCache, source, eventType, id, Nothing, Nothing, Nothing, data)) Then
Me.WriteHeader(source, eventType, id)
Dim text1 As String = String.Empty
If (Not data Is Nothing) Then
text1 = data.ToString
End If
Me.WriteLine(text1)
Me.WriteFooter(eventCache)
End If
End Sub
False)> _
Public Overrides Sub TraceData(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal ParamArray data As Object())
If ((Me.Filter Is Nothing) OrElse Me.Filter.ShouldTrace(eventCache, source, eventType, id, Nothing, Nothing, Nothing, data)) Then
Me.WriteHeader(source, eventType, id)
Dim builder1 As New StringBuilder
If (Not data Is Nothing) Then
Dim num1 As Integer = 0
Do While (num1 < data.Length)
If (num1 <> 0) Then
builder1.Append(", ")
End If
If (Not data(num1) Is Nothing) Then
builder1.Append(data(num1).ToString)
End If
num1 += 1
Loop
End If
Me.WriteLine(builder1.ToString)
Me.WriteFooter(eventCache)
End If
End Sub
False)> _
Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal message As String)
If ((Me.Filter Is Nothing) OrElse Me.Filter.ShouldTrace(eventCache, source, eventType, id, message, Nothing, Nothing, Nothing)) Then
Me.WriteHeader(source, eventType, id)
Me.WriteLine(message)
Me.WriteFooter(eventCache)
End If
End Sub
False)> _
Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal format As String, ByVal ParamArray args As Object())
If ((Me.Filter Is Nothing) OrElse Me.Filter.ShouldTrace(eventCache, source, eventType, id, format, args, Nothing, Nothing)) Then
Me.WriteHeader(source, eventType, id)
If (Not args Is Nothing) Then
Me.WriteLine(String.Format(CultureInfo.InvariantCulture, format, args))
Else
Me.WriteLine(format)
End If
Me.WriteFooter(eventCache)
End If
End Sub
Private Sub WriteFooter(ByVal eventCache As TraceEventCache)
If (Not eventCache Is Nothing) Then
Me.IndentLevel += 1
If Me.IsEnabled(TraceOptions.ProcessId) Then
Me.WriteLine(("ProcessId=" & eventCache.ProcessId))
End If
If Me.IsEnabled(TraceOptions.LogicalOperationStack) Then
Me.Write("LogicalOperationStack=")
Dim stack1 As Stack = eventCache.LogicalOperationStack
Dim flag1 As Boolean = True
Dim obj1 As Object
For Each obj1 In stack1
If Not flag1 Then
Me.Write(", ")
Else
flag1 = False
End If
Me.Write(obj1.ToString)
Next
Me.WriteLine(String.Empty)
End If
If Me.IsEnabled(TraceOptions.ThreadId) Then
Me.WriteLine(("ThreadId=" & eventCache.ThreadId))
End If
If Me.IsEnabled(TraceOptions.DateTime) Then
Me.WriteLine(("DateTime=" & eventCache.DateTime.ToString("o", CultureInfo.InvariantCulture)))
End If
If Me.IsEnabled(TraceOptions.Timestamp) Then
Me.WriteLine(("Timestamp=" & eventCache.Timestamp))
End If
If Me.IsEnabled(TraceOptions.Callstack) Then
Me.WriteLine(("Callstack=" & eventCache.Callstack))
End If
Me.IndentLevel -= 1
End If
End Sub
Private Sub WriteHeader(ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer)
Dim oldColor As ConsoleColor = Console.ForegroundColor
Select Case eventType
Case TraceEventType.Error
Console.ForegroundColor = ConsoleColor.Red
Case TraceEventType.Critical
Console.ForegroundColor = ConsoleColor.Magenta
Case TraceEventType.Information
Console.ForegroundColor = ConsoleColor.White
'Case TraceEventType.Resume
'Case TraceEventType.Start
'Case TraceEventType.Suspend
'Case(TraceEventType.Transfer)
'Case TraceEventType.Verbose
Case TraceEventType.Warning
Console.ForegroundColor = ConsoleColor.Yellow
End Select
Me.Write(String.Format(CultureInfo.InvariantCulture, "{0} {1}:", New Object() {source, eventType.ToString}))
Console.ForegroundColor = oldColor
Me.Write(String.Format(CultureInfo.InvariantCulture, " {0} : ", New Object() {id.ToString(CultureInfo.InvariantCulture)}))
End Sub
End Class
The methods that handle the headers in the TextWriteListener are private (WriteHeader and WriterFooter) so we need to override them. Reflector comes very handy in this cases.
No to test it Create a Vb Console Application:
Module Module1
Sub Main()
My.Application.Log.WriteEntry("Error!", TraceEventType.Error)
My.Application.Log.WriteEntry("Warning", TraceEventType.Warning)
My.Application.Log.WriteEntry("Info", TraceEventType.Information)
My.Application.Log.WriteEntry("Info", TraceEventType.Critical)
Trace.TraceError("An Error Happened!")
Trace.TraceInformation("Just letting you know!")
Trace.TraceWarning("Watch the road ahead")
End Sub
End Module
And use a simple configuration file like the following:
xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add name="ColorLog" />
listeners>
trace>
<sources>
This section defines the logging configuration for My.Application.Log -->
<source name="DefaultSource" switchName="DefaultSwitch">
<listeners>
<add name="ColorLog"/>
listeners>
source>
sources>
<switches>
<add name="DefaultSwitch" value="Verbose" />
switches>
<sharedListeners>
<add name="ColorLog" type="Mrojas.ColorTraceListener, ColorTraceListener" />
sharedListeners>
system.diagnostics>
configuration>