views:

90

answers:

2

I am trying to build an error handler for my desktop application. The code Is in the class ZipCM.ErrorManager listed below.

What I am finding is that the outputted file is not giving me the correct info for the StackTrace.

Here is how I am trying to use it:

Try
     '... Some stuff here!

     Catch ex As Exception
            Dim objErr As New ZipCM.ErrorManager
            objErr.Except = ex
            objErr.Stack = New System.Diagnostics.StackTrace(True)
            objErr.Location = "Form: SelectSite (btn_SelectSite_Click)"
            objErr.ParseError()
            objErr = Nothing
        End Try

Here is the class:

    Imports System.IO

Namespace ZipCM

    Public Class ErrorManager

        Public Except As Exception
        Public Location As String
        Public Stack As System.Diagnostics.StackTrace

        Public Sub ParseError()
            Dim objFile As New StreamWriter(Common.BasePath & "error_" & FormatDateTime(DateTime.Today, DateFormat.ShortDate).ToString().Replace("\", "").Replace("/", "") & ".log", True)
            With objFile
                .WriteLine("-------------------------------------------------")
                .WriteLine("-------------------------------------------------")
                .WriteLine("An Error Occured At: " & DateTime.Now)
                .WriteLine("-------------------------------------------------")
                .WriteLine("LOCATION:")
                .WriteLine(Location)
                .WriteLine("-------------------------------------------------")
                .WriteLine("FILENAME:")
                .WriteLine(Stack.GetFrame(0).GetFileName())
                .WriteLine("-------------------------------------------------")
                .WriteLine("LINE NUMBER:")
                .WriteLine(Stack.GetFrame(0).GetFileLineNumber())
                .WriteLine("-------------------------------------------------")
                .WriteLine("SOURCE:")
                .WriteLine(Except.Source)
                .WriteLine("-------------------------------------------------")
                .WriteLine("MESSAGE:")
                .WriteLine(Except.Message)
                .WriteLine("-------------------------------------------------")
                .WriteLine("DATA:")
                .WriteLine(Except.Data.ToString())
            End With
            objFile.Close()
            objFile = Nothing
        End Sub

    End Class

End Namespace

What is happenning is the .GetFileLineNumber() is getting the line number from 'objErr.Stack = New System.Diagnostics.StackTrace(True)' inside my Try..Catch block. In fact, it's the exact line number that is on.

Any thoughts of what is going on here, and how I can catch the real line number the error is occuring on?

+2  A: 

Edit: Changed the code to account for the Exception.StackTrace being a string rather than a real StackTrace

You're creating a new StackTrace, so then it will be for the line you're declaring it on, if you want the line number of the original exception, use the stack trace in Exception.StackTrace.

I think you're being a little confused, I can't see why you create the new StackTrace at all?

Edit: Added more bits to the answer here since easier to see the syntax than in a comment

Currently you have the line

 objErr.Stack = New System.Diagnostics.StackTrace(True)

Which means that you're creating a whole new stacktrace, starting when you're creating it.

Instead change that line to:

objErr.Stack = New System.Diagnostics.StackTrace(ex, True)

Which will have the stacktrace from when the error actually happened.

Edit: Added complete sample:

Private Sub a1()
    Try
        a2()
    Catch ex As Exception
        Dim st As New StackTrace(True)
        Debug.WriteLine(String.Format("ST after exception, will give line number for where st was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))

        st = New StackTrace(ex, True)
        Debug.WriteLine(String.Format("ST after exception using exception info, will give line number for where exception was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))
    End Try
End Sub

Private Sub a2()
    Dim st As New StackTrace(True)
    Debug.WriteLine(String.Format("ST before exception, will give line number for where st was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))
    Dim b As Integer = 0
    Dim a As Integer = 1 / b
End Sub
ho1
I am confused. Where should that go in my code?
Kevin Pirnie
@Kevin: Please see my updated answer under the line prefixed with `Edit:` for a better explanation.
ho1
sorry, but tht only brings errors. something about .StackTrace being a string, and GetFrame is not a method or property of it...
Kevin Pirnie
@Kevin: Sorry, my mistake, I forgot that it's a string in the `Exception`, you do have to create a new StackTrace, but you have to send the `Exception` in as a parameter, so it should be `objErr.Stack = New System.Diagnostics.StackTrace(ex, True)`. I've updated my answer above which might be easier to read.
ho1
well.... we are getting somewhere, no more string issue, however there is no line number, no file, etc?
Kevin Pirnie
@Kevin: I've added a complete code sample. I just create a new WinForms project, create an event handler for the form's `Load` event and call the `a1` method from that handler it all works as expected for me.
ho1
that is the basics of what I am doing as well.... problem is, I am not getting the line number or the filename out of the stacktrace.In my class, do I need to keep 'Public Stack As New System.Diagnostics.StackTrace' or should I change to to something else because I am already passing it to the class in the first place?
Kevin Pirnie
@Kevin: 'Public Stack As New System.Diagnostics.StackTrace'... I can't see that in your sample code. You might want to refresh your question with your current code, it's probably going to be some tiny problem with it.
ho1
it's right in the class above
Kevin Pirnie
@Kevin: There's no `New` in that line though, so that's why I was thinking that maybe your code looks different now?
ho1
A: 

You do not need to include a Stack property for your ErrorManager, because you have access to the stack trace through the exception.

From experience, I would create a Shared Sub Write(ex As Exception, location As String) method on the ErrorManager, and call in your Catch statement as:

ZipCM.ErrorManager.Write(ex, "Form: SelectSite (btn_SelectSite_Click)")

This change results in cleaner code, reduces the need to write lots of code in each Catch statement, and allows you to change the implementation of Write without having to revisit/rework/refactor each Catch statement.

For instance, you can change the Write method to also call Debug.WriteLine(ex) so you can see which exceptions you are handling during debugging without having to open the file. Moreover, you may want to include WriteNotify method that displays a message box of the exception then calls the Write method to log the exception.

AMissico