Jump to content

Logging Exception with StackTrace

Posted on:September 15, 2011 at 02:00 AM

C# language has a great Exception Handling mechanism build-in. If something in not predictable during compile time developer can easily embed that piece of code in try{ (...) } catch{ (...) } and say “case closed”. Sample code taken from MSDN:

class ExceptionTest
{
    static double SafeDivision(double x, double y)
    {
        if (y == 0)
            throw new System.DivideByZeroException();
        return x / y;
    }
    static void Main()
    {
        // Input for test purposes. Change the values to see
        // exception handling behavior.
        double a = 98, b = 0;
        double result = 0;

        try
        {
            result = SafeDivision(a, b);
            Console.WriteLine("{0} divided by {1} = {2}", a, b, result);
        }
        catch (DivideByZeroException e)
        {
            Console.WriteLine("Attempted divide by zero.");
            //Logger.Error("Attempted divide by zero.")
        }
    }
}

Works like a charm… but this was very simple scenario. In more advanced scenarios we - developers - would like to get some more feedback, then just a logged information like:Attempted divide by zero. In business application a lot of other factors in involved. So it is necessary to have proper feedback information when something goes wrong. I’ve also faced that problem. Not sufficient information was provided with the bug description and we were unable to reproduce and fix the bug.

At that moment I’ve decided to do the obvious step. Serialize Exception object and save in separate log file :D

Code that realizes my idea is showed below:

public class ExceptionXElement : XElement
    {
        public ExceptionXElement(Exception exception)
            : base(new Func<XElement>(() =>
            {
                if (exception == null)
                {
                    throw new ArgumentNullException("exception");
                }
                XElement root = new XElement
                  (exception.GetType().ToString());

                if (exception.Message != null)
                {
                    root.Add(new XElement("Message", exception.Message));
                }

                if (exception.StackTrace != null)
                {
                    root.Add
                    (
                      new XElement("StackTrace",
                        from frame in exception.StackTrace.Split('n')
                        let prettierFrame = frame.Substring(6).Trim()
                        select new XElement("Frame", prettierFrame))
                    );
                }

                if (exception.Data.Count > 0)
                {
                    root.Add
                    (
                      new XElement("Data",
                        from entry in
                            exception.Data.Cast<DictionaryEntry>()
                        let key = entry.Key.ToString()
                        let value = (entry.Value == null) ?
                          "null" : entry.Value.ToString()
                        select new XElement(key, value))
                    );
                }

                if (exception.InnerException != null)
                {
                    root.Add
                    (
                      new ExceptionXElement
                        (exception.InnerException)
                    );
                }

                return root;
            })())
        { }
    }

Code above is nicely wrapped in a function that saves XElement into single file.