Click here to Skip to main content
15,880,972 members
Articles / Programming Languages / Visual Basic
Article

World's easiest Trace function

Rate me:
Please Sign up or sign in to vote.
4.13/5 (8 votes)
3 Mar 2005CPOL3 min read 74.3K   39   12
Add tracing capability to your app with one easy function

Introduction

Debugging your way through code can be boring and tiring. When you're hunting down a bug, it helps if you can zero right in on the problem. By adding a simple trace file to your app, you can pinpoint the exact sub or function where things went wrong.

With a bit more work, you can configure your app to turn on or turn off writing to the trace file as needed. You can also start with a fresh trace file every time your app is loaded.

With the trace mechanism in place, you can run your app until things go wrong. Then by examining the trace file, you know just where to turn in your code.

This simple approach uses .NET's StackTrace feature to keep track of where users have been as they work with your app.

Discussion

StackTrace is part of the System.Diagnostics namespace, so you will want to include a reference to that in your project with an Imports statement at the beginning of your class or module.

StackTrace is a pile of StackFrames. Each StackFrame holds information about each function or sub as your application accesses it. Every time a function or sub is accessed, information in the form of a StackFrame about it is pushed onto the top of the StackTrace. This information is available as a string, which we can easily parse to extract just the information we want.

There are two parts to using this mechanism: writing a short subroutine to write material to the trace file, and adding a line to each sub or function calling that subroutine. Let's look at the subroutine first. I've simplified the code somewhat to make it easier to follow, and I use some constants that I've defined elsewhere; their values should be obvious.

VB.NET
Friend Sub Tracer()
       Dim texttoadd As String
       Dim logtext() As String
       Dim fileline() As String
       Dim fs As StreamWriter
       Dim strace As New StackTrace(True)
       Try
           If Not File.Exists(TRACE_LOG) Then
               fs = File.CreateText(TRACE_LOG)
               fs.Write("Trace Log " & Format(Now) & CR & CR)
               fs.Flush()
               fs.Close()
           End If
           logtext = strace.GetFrame(1).ToString.Split(SPACE)
           fileline = logtext(6).Split(BACKSLASH)
           Dim i As Integer = fileline.GetUpperBound(0)
           texttoadd = logtext(0) & COLON & SPACE & _
                fileline(i).Substring(0, fileline(i).Length - 2)
           fs = File.AppendText(TRACE_LOG)
           fs.WriteLine(texttoadd)
           fs.Flush()
           fs.Close()
       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

The StreamWriter is the mechanism used to write the information to the log file. If you are unfamiliar with writing streams, check out the .NET documentation on the topic.

The StackTrace is created using the optional True parameter to indicate that we want the trace to include information about the file the function or subroutine belongs to. The nice thing about the StackTrace is that it holds information about everything that has already happened in the application. In fact, the information we want is not even on the top of the stack--it's one item down, because the last item pushed onto the stack is the call to our Tracer() routine. That's why when we capture the StackFrame we want, we have to get the second item (in a zero-based array).

We can confidently split the StackFrame to an array because these entries always have the same format. The first element in the array will contain the name of the sub or function we want to capture. The last element will have the name of the source file as well as the line number and offset. A typical logtext array will look something like this:

(0): "myFunction"
(1): "at" 
(2): "offset" 
(3): "87" 
(4): "in" 
(5): "file:line:column"
(6): "C:\ProgramFiles\VS\MyProject\MyModule.vb:12345:67

We can then confidently split the last element of logtext into an array, using the backslash as the delimiter. We only care about the last element of that array. Note, though, that the last element actually ends with a line-end character, so we must parse that away before we write to our trace file. (If you don't parse it away, your trace file will end up double-spaced, which you might prefer.)

The second part of the setup is easy: Just add a call to Tracer() in every function or sub you want to include in your trace file:

VB.NET
Private Sub DoSomething(somethingToDo as String)
   Tracer()
   somethingToDo = somethingToDo & somethingElse
   ...
End Sub

To turn the trace on and off at will, you can add a global Boolean variable to your code, and then examine the state of that variable at run-time to decide if you are tracing or not. The easiest way to do this is to pass a command-line argument:

VB.NET
Class MyMainForm
Public traceIt as Boolean = False

Public Sub Main()
   If Environment.CommandLine.IndexOf("/t")> 0 then traceIt = True

   ...
End Sub

Private Sub DoSomething(somethingToDo as String)
   If traceIt Then Tracer()
   somethingToDo = somethingToDo & somethingElse
   ...
End Sub

Finally, to start a new trace file every time you start your app, add a line to the main program block to delete the existing file:

VB.NET
If File.Exists(TRACE_LOG) then File.Delete(TRACE_LOG)

You can apply the same technique in a Try/Catch block as well, and incorporate the exception in the trace file. But I'll leave that for you to play with.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
Terpy is a consultant reluctantly based in Olympia, Wash. She'd much rather be back in Maine, where the ocean is on the correct side of the road. She is largely a self-taught programmer who clings jealously to her bad habits. Handbells, anyone?

Comments and Discussions

 
GeneralGreat Idea [modified] Pin
Eradikator13-Feb-07 21:51
Eradikator13-Feb-07 21:51 
This is exactly that what i searched for.

Many Thanks to you.

Peer Royla from Germany

Edit: I Prefer to get the Class of the Funktion in stead the Filename, someone has an Idea?

2nd Edit:
Somewhat easier ->
Imports System.Diagnostics<br />
Public Class StackTraceTest<br />
    Public Function FU_GetSUBFUCLASS(ByRef Trans_SUBFU As String, ByRef Trans_CLASS As String, ByRef Trans_Temp As Integer) As Boolean<br />
        <br />
        Dim strace As New StackTrace(True)<br />
        Dim sFrame As New StackFrame<br />
       <br />
        Trans_CLASS = strace.GetFrame(1).GetMethod().DeclaringType.Name<br />
        Trans_SUBFU = strace.GetFrame(1).GetMethod().Name<br />
        <br />
        Return True<br />
    End Function<br />
End Class

SUBFU returns the Calling-Funktion, and CLASS the Class the Funktion is depending on.



-- modified at 7:55 Friday 16th February, 2007
Questionspace in path Pin
mjstraka19-Aug-06 18:24
mjstraka19-Aug-06 18:24 
AnswerRe: space in path Pin
terpy19-Aug-06 19:11
terpy19-Aug-06 19:11 
GeneralSystem.Diagnostics members Pin
Marcus Poilus31-Mar-06 2:49
Marcus Poilus31-Mar-06 2:49 
AnswerRe: System.Diagnostics members Pin
terpy31-Mar-06 5:10
terpy31-Mar-06 5:10 
GeneralRe: System.Diagnostics members Pin
Marcus Poilus31-Mar-06 6:16
Marcus Poilus31-Mar-06 6:16 
AnswerRe: System.Diagnostics members Pin
terpy31-Mar-06 6:39
terpy31-Mar-06 6:39 
GeneralRe: System.Diagnostics members Pin
Marcus Poilus31-Mar-06 7:42
Marcus Poilus31-Mar-06 7:42 
GeneralSimple is good Pin
Jason Titcomb16-Apr-05 3:13
Jason Titcomb16-Apr-05 3:13 
GeneralRelease Mode Pin
Neil Baliga4-Mar-05 6:15
Neil Baliga4-Mar-05 6:15 
GeneralRe: Release Mode Pin
terpy7-Mar-05 11:58
terpy7-Mar-05 11:58 
Generallog4net Pin
Uwe Keim3-Mar-05 17:08
sitebuilderUwe Keim3-Mar-05 17:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.