Yes I do want to do something like this and Ive managed to work out how to do it. All I needed to do in the end was use the StackTrace class to retrieve the previous frame and then examine it to get the MethodBase object and in turn the name of the method. Here is the code I used:
Code:
Public Sub Enter(Optional ByVal Message As String = "")
Dim Caller As StackFrame
Dim StackTrace As New StackTrace()
Dim CallerName As String
Dim Indent As String
Dim FileName As String
Caller = StackTrace.GetFrame(1)
CallerName = Caller.GetMethod.Name Get name of calling method
FileName = Caller.GetFileName ** Method not yet implemented **
Indent = IndentEnter(Caller.GetMethod)
If Message <> "" Then
WriteLine(Indent + "Entering " + CallerName + "() <" + Message + ">")
Else
WriteLine(Indent + "Entering " + CallerName + "()")
End If
End Sub
The reason I wanted to do it is because I am implementing a trace listener to log to a file when certain methods are entered and exited (in order to aid the debugging of my program). I feal this is a good method to use because I only have to disable the TRACE compilation constant to prevent the logging.
Here is the code that I used for those that are interested:
Code:
Imports System.IO
Imports System.Reflection
Imports System.Diagnostics
Public Class MainTraceListener
Inherits TraceListener
Private m_IndentStorer As New ArrayList()
Private Structure MethodIndent
Dim IndentLevel As Integer
Dim Method As MethodBase
End Structure
Create a log file named PROFILE.LOG
Dim m_StreamWriter As New StreamWriter("PROFILE.LOG")
Public Overloads Overrides Sub Write(ByVal Message As String)
Display indentation and time only at beginning of line
If NeedIndent Then
m_StreamWriter.Write("[" + Now.ToString + " " + _
CStr(Now.Millisecond) + "] ")
WriteIndent()
End If
m_StreamWriter.Write(Message)
m_StreamWriter.Flush()
End Sub
Public Overloads Overrides Sub WriteLine(ByVal Message As String)
Use the Write method to display an extire line
Write(Message + ControlChars.CrLf)
Next line must be indented and current time must be displayed
NeedIndent = True
End Sub
Public Sub Note(ByVal Note As String)
WriteLine("***** " + Note + " *****")
End Sub
Private Function IndentEnter(ByVal Method As MethodBase) As String
Dim MethodIndent As New MethodIndent()
Dim Indent As String
If m_IndentStorer.Count = 0 Then
MethodIndent.IndentLevel = 0
MethodIndent.Method = Method
m_IndentStorer.Add(MethodIndent)
Exit Function
Else
MethodIndent.IndentLevel = _
CType(m_IndentStorer(m_IndentStorer.Count - 1), _
MethodIndent).IndentLevel + 1
MethodIndent.Method = Method
m_IndentStorer.Add(MethodIndent)
End If
Indent = Space(IndentSize * MethodIndent.IndentLevel)
Return Indent
End Function
Private Function IndentLeave(ByVal Method As MethodBase) As String
Search for method
Dim SearchMethodIndent As MethodIndent
Dim Indent As String
For Each SearchMethodIndent In m_IndentStorer
If SearchMethodIndent.Method Is Method Then
Found method. Do indent
Indent = Space(IndentSize * SearchMethodIndent.IndentLevel)
Remove method indent data from arraylist
m_IndentStorer.Remove(SearchMethodIndent)
Return Indent
End If
Next
End Function
Public Sub Enter(Optional ByVal Message As String = "")
Dim Caller As StackFrame
Dim StackTrace As New StackTrace()
Dim CallerName As String
Dim Indent As String
Dim FileName As String
Caller = StackTrace.GetFrame(1)
CallerName = Caller.GetMethod.Name
FileName = Caller.GetFileName ** Method not yet implemented **
Indent = IndentEnter(Caller.GetMethod)
If Message <> "" Then
WriteLine(Indent + "Entering " + CallerName + "() <" + Message + ">")
Else
WriteLine(Indent + "Entering " + CallerName + "()")
End If
End Sub
Public Sub Leave(Optional ByVal Message As String = "")
Dim Caller As StackFrame
Dim StackTrace As New StackTrace()
Dim CallerName As String
Dim Indent As String
Caller = StackTrace.GetFrame(1)
CallerName = Caller.GetMethod.Name
Indent = IndentLeave(Caller.GetMethod)
If Message <> "" Then
WriteLine(Indent + "Exiting " + CallerName + "() <" + Message + ">")
Else
WriteLine(Indent + "Exiting " + CallerName + "()")
End If
End Sub
End Class
I then instantiated the class in a shared module:
Code:
Module TracerObject
Trace listener
Public Tracer As New MainTraceListener()
Sub New()
Trace.Listeners.Add(Tracer)
End Sub
End Module
Then, I used the tracer (in a different class) as follows:
Code:
Public Sub Start()
Tracer.Enter() Log method start
Only start server if it is stopped
If ServerState.CurrentState <> ObjectState.Stopped Then Exit Sub
Server is now starting
ServerState.ClearError()
ServerState.ChangeState(ObjectState.Starting, True)
Tracer.Note("Starting listener")
StartListener()
Tracer.Leave() Log method end
End Sub
Here is the resulting output that has been sent to the file PROFILE.LOG (along with the output of a few other methods):
Code:
[07/05/2003 19:55:25 779] Entering .ctor()
[07/05/2003 19:55:25 809] Exiting .ctor()
[07/05/2003 19:55:28 142] Entering Start()
[07/05/2003 19:55:28 152] Entering doStateChanged()
[07/05/2003 19:55:28 182] Exiting doStateChanged()
[07/05/2003 19:55:28 192] ***** Starting listener *****
[07/05/2003 19:55:28 192] Exiting Start()
[07/05/2003 19:55:28 373] Entering doStateChanged()
[07/05/2003 19:55:28 393] Exiting doStateChanged()
[07/05/2003 19:55:28 423] Server queue processor started.
[07/05/2003 19:55:46 649] Entering Shutdown()
[07/05/2003 19:55:46 649] Entering doStateChanged()
[07/05/2003 19:55:46 649] Exiting doStateChanged()
[07/05/2003 19:55:46 689] Server queue processor exiting.
[07/05/2003 19:55:46 699] Entering doStateChanged()
[07/05/2003 19:55:46 839] Exiting doStateChanged()
[07/05/2003 19:55:46 839] Exiting Shutdown()
Methods markey .ctor are constructor methods. I would have like to have included the name of the file that the method was running from but after checking the documentation, Microsoft hasnt implemented the StackFrame.GetFileName method.
I hope that this has explained what I am up to and maybe a few people might find it interesting. The code isnt up to my ideal standard because I needed a quick and dirty solution but if anyone wants me to explain anything just ask.
Jamie