Easy error tracking in your applications

Posted by Filip Ekberg on March 26 2013 11 Comments

Over and over again I see developers re-implementing error tracking, I’ve been there myself. One of the reasons to this I think is because many of the tracking tools out there add too much noise and are just cumbersome to use. In many cases the biggest problem is that you need error logging too late, meaning that you want the logging once the error has already occurred. It’s of course cleaver to say that you should always think about potential errors from the start, because let’s face it we all write applications that may have unexpected exceptions.

Another problem is that if we do decide to log errors in our applications, where do we store them and how do we collect the logs? Luckily there’s tools out there that can help us on the way. One that I most recently came across called Raygun. Raygun is a product from the company Mindscape that have some very interesting products in their family.

Error handling just got awesome!

The punch line of Raygun is quoted above, a tool that makes error handling awesome. Let’s clear something up right before we take a look at Raygun , there are multiple providers supplied for Raygun: JavaScript, .NET, Java, PHP and Cold Fusion. Didn’t find the language you work with? Don’t worry, there’s a REST API for you RESTafarians!

So there are providers for Raygun, but what does it actually do?

Imagine that you have your web application written in PHP, ASP.NET or just something that is using JavaScript. Now you want some centralized place where you can store errors in either of these applications, be it severe exceptions or just notices about something unexpected.

If you’ve found yourself writing an error tracker where you just dump the Stack Trace and the exception message into a database, then this is certainly something for you. Imagine that if your customer calls up and says that he recently got the yellow screen of death but don’t know what he was doing or really exactly what time it was.

Now imagine that you were to access your centralized error tracker and you’d have all of the information that you would need to find the error in the code base including:

  • Time of error
  • How many times the current error have occurred
  • Information about the system the user is using
  • The exception message
  • A Stack Trace

That is Raygun! A way to track your errors in a very easy way and the presentation is just beautiful.

The information you’ll get out of each error report of course depends on the data that you supply Raygun with. Take a look at the REST API to get an idea of all the data that you possibly could supply Raygun with.

Enough with what, let’s look at the how! Let’s look at some code!

For this demo I’m going to setup 2 things an ASP.NET MVC 4 Application and a Class Library that will simulate a data store where I can search for people. The web front will allow me to search for people inside my collection and when I wrote this example Raygun actually helped me detect one of the errors I were getting, let’s call this “TrackCeption”.

First of all let’s look at the library. There’s a very easy class that represents the person, it simply has a property called “Name” inside it.

public class Person
{
    public string Name { get; set; }
}

Secondly there’s a class that handles the search requests, I call this RequestHandler. To set this up we need to create a new list of people, in this case it’s just going to be a static collection of people as you can see here:

private static IEnumerable<Person> _people;
public RequestHandler()
{
    _people = new Person[] {  
            new Person { Name = "Filip" },
            new Person { Name = "Sofie" },
            new Person { Name = "Johan" },
            new Person { Name = "Anna" },
        };
}

Now we need a way to retrieve all these people and I like creating asynchronous methods where the operations might be time consuming and in this case I know that it will take 2 seconds to retrieve the list of people:

public Task<IEnumerable<Person>> GetPeopleAsync()
{
    return Task<IEnumerable<Person>>.Factory.StartNew(() => {

        Thread.Sleep(2000);

        return _people;
    });
}

This leaves us with implementing a method that lets us search for people in the collection. So far we don’t care if the list has been empty or not but when we search we want to report an error when there’s no people in the list. Let’s just assume that this is an exception in the application and the end user will always search for people that are in the list.

Let’s install Raygun!

Installing Raygun is as easy as saying “I’ll soon blast all my errors with this Raygun!”; simply bring up the NuGet package manager and write the following:

PM> Install-Package Mindscape.Raygun4Net

This will install Raygun into your class library! There’s a couple of more things that we need to do in order to get Raygun up and running:

  • Create an account and an application at Raygun.io
  • Add the API Key to your application

Creating a Raygun account is free for 30 days and you’ll need to do it in order to start tracking your errors. Once you’ve setup an application on Raygun you can retrieve the API Key from the “Application Settings” menu like you can see in the following image:

RaygunAPIKey

We don’t need to add the API Key just yet, we’ll add that in the application configuration file of the project that will use our library later on (in this case the MVC 4 project).

Now, bringing in Raygun into our application using NuGet will allow us to write the following:

new RaygunClient().Send(new Exception(string.Format("People with name `{0}` not found", name)));

That will create a Raygun client and send a new exception with the message you can see to the Raygun servers and passing it the API Key that we will provide later on. So let’s take a look at how the method that will find people in the colleciton will look like. This one also takes 2 seconds to execute so we will have this one asynchronous as well, we don’t need to do it but I take every chance I got to play with asynchronous programming.

public Task<IEnumerable<Person>> FindPeopleAsync(string name)
{
    return Task<IEnumerable<Person>>.Factory.StartNew(() =>
    {
        Thread.Sleep(2000);

        var people = _people.Where(x => x.Name.Contains(name)).ToList();

        if (people == null || !people.Any())
        {
            new RaygunClient().Send(new Exception(string.Format("People with name `{0}` not found", name)));
        }

        return people;
    });
}

The method will look for people with the name of the value that we passed to the method and if there’s no people found it will send this notice to Raygun. You might think to yourself that this isn’t really a good exception at all, but for the purpose of the demo, let’s just look pass that. Also a bird whispered into my ears that Mindscape is working on adding other message types than exceptions to Raygun, but that’s in the future.

This leaves us with a structure looking like the following:

RaygunDemoLibrary

We are now ready to use our library!

Create a new ASP.NET MVC 4 Application, I named mine RaygunDemo. The first thing that we are going to do is to add Raygun to this project as well, install it into the ASP.NET MVC 4 project using NuGet as we did before and open up web.config once this is done.

In order for us to get Raygun working we need to add our API Key. To do this we first need to add an element inside <configSections>:

<section name="RaygunSettings" type="Mindscape.Raygun4Net.RaygunSettings, Mindscape.Raygun4Net"/>

This will allow us to add a configuration like this:

<RaygunSettings apikey="YOUR_API_KEY_HERE" />

It should look something like this in your web.config, with a lot of extra stuff as well of course:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="RaygunSettings" type="Mindscape.Raygun4Net.RaygunSettings, Mindscape.Raygun4Net"/>
  </configSections>
  <RaygunSettings apikey="YOUR_API_KEY_HERE" />
</configuration>

Remember I said that Raygun helped me find an exception in my application when setting up the demo application? This is because I told Raygun to submit all the application errors. In the ASP.NET MVC 4 project, open up Global.asax and add the following method, this one will be run every time there’s an error in the application:

protected void Application_Error()
{
    var exception = Server.GetLastError();
    new RaygunClient().Send(exception);
}

This means that every time that we get an application error Raygun will be noticed of this and the entire Stack Trace, Computer info and such will be passed into Raygun!

All there’s left to add now is the Home controller and the view, the Home controller consists of two asynchronous actions that will use the library we just created. One will return a view and the other will return a Json result:

public async Task<ActionResult> Index()
{
    var requestHandler = new RequestHandler();
    var people = await requestHandler.GetPeopleAsync();

    return View(people);
}
public async Task<JsonResult> Search(string search)
{
    var requestHandler = new RequestHandler();
    var people = await requestHandler.FindPeopleAsync(search);
           
    return Json(people);
}

The view is equally simple, it only has a text box that allows us to search for names and then it has a list that shows all the people. Once a key is pressed inside the text box an event is fired that requests the people that have a name containing that part:

@model IEnumerable<RaygunDemoLibrary.Person>

<div>
    <span>Search: </span>
    <span><input id="search" type="search" /></span>
</div>
<h2>People</h2>
<div id="people">
    @foreach (var person in Model)
    {
        <div class="person">
            <span>@person.Name</span>
        </div>
    }
</div>

@section scripts{
    <script>
        $("#search").keyup(function () {
            searchValue = $("#search").val();
            $.post("/Home/Search", { search:  searchValue}, function (data) {
                var peopleDiv = $("#people");
                peopleDiv.html("");
                data.forEach(function (person) {
                    name = person.Name.replace(searchValue, "<strong>" + searchValue + "</strong>");
                    peopleDiv.append("<div class='person'><span>" + name + "</span></div>");
                });
            });
        });
    </script>
}

If I start this and search for a name that exists and one that doesn’t it will look like the following:

RaygunReportError

Funny thing is that we didn’t actually notice anything when we searched for something that didn’t exist. So how do we know that this worked?

Raygun comes with an Amazing dashboard that will give you an overview of everything including all the recent errors, how many errors/ignored errors you have and much more like you see in this image (click to enlarge):

RaygunReport

Finally this is what it looks like when you go into details about an exception, you’ll have a graph over how many times and when it occurred and then you have very much details that will help you Raygun the errors!

RaygunStackTrace

If you’re unable to add code to your current website you can simply add a HTTP Module and a config value! Which means you could simply add this in your web.config provided you have the dll as well of course!

<httpModules>
  <add name="RaygunErrorModule" type="Mindscape.Raygun4Net.RaygunHttpModule"/>
</httpModules>

I really recommend giving Raygun a try! Let me know what you think of it and if you have any alternatives that are equally awesome!

Vote on HN

11 Responses to Easy error tracking in your applications

  1. JorgeNo Gravatar says:

    All very sweet…and what happens when you don’t have internet and errors are occurring?
    Must I rely on the single point of failure which is this website?
    And bandwidth costs for the information logging?

    This is all very eye candy…but the bottom line is COSTS! We want to reduce not to increase them.
    PaaS like these aren’t really what companies want..companies want to have the full control of doing things!

  2. Pingback: Dew Drop – March 26, 2013 (#1,514) | Alvin Ashcraft's Morning Dew

  3. Phillip HaydonNo Gravatar says:

    Jorge, I dear say, if you don’t have internet, no one is visiting your website to begin with.

    But I’ll assume you meant, when they (Raygun) don’t have internet, I would be willing to bet that any errors lost during any downtime would most likely be logged before/after the internet is available for them again.

    And what about cost of bandwidth? Damn are you sending THAT many exceptions that that bandwidth is a cost? I think you have FAR greater issues at hand than worrying about Bandwidth, which by the way looking at Amazon and Azure, is dirty cheap.

    If you don’t mind incurring the cost of building the infrastructure around log4net, NLog, etc etc then by all means, incur that cost. Then there’s the cost of monitoring the logs, filtering them yourself, administrating the logs. That costs a HELL of a lot more in developer time than a Subscription. In-fact 1 app costs less than 1 hour of developer time.

    Lets go back to internet again on a non-website scenario. You’re building a desktop app, which is still going to need the internet to send logs back, so you have to write ALL that yourself. Cool. But what if the internet goes down, then you need to write all the code to persist locally and send those logs later.

    Any way you look at it, Raygun, or any other Error handling provider, is going to cut your costs, not increase them.

  4. John-Daniel TraskNo Gravatar says:

    Hi Jorge,

    For occasionally connected systems (e.g. Phones / Tablets) we’re working on batching the messages for when connectivity is available. I’m sure you’re not planning to somehow access logs on a users cell phone, but getting the information about the crash later when they have connectivity will solve that and send you the data.

    Regarding the ‘single point of failure’, Raygun runs across a load balancer, across availability zones with Amazon with 3 levels of backup (touch wood, it’ll probably all fail now that I’ve said that out loud!). Realistically this is likely more than many companies are doing now even for their primary systems. You’re in good hands with Raygun :-)

    Regarding your ‘managing costs’ comment – an engineer who can be billing $80 – $200 per hour depending on country and skill level. I don’t think you can argue that a service that costs, say $29 a month is really increasing costs — more likely you’re blowing costs as soon as you tell your engineer to spend a few days building your own infrastructure.

    Appreciate the feedback and certainly occasionally connected systems support is something we’re doing.

    Also, thanks for the blog post Filip, very much appreciated :-)

    John-Daniel Trask
    Co-founder of Mindscape (creators of Raygun)

  5. Brian RosamiliaNo Gravatar says:

    >have any alternatives that are equally awesome!

    Pre-Emptive analytics has a very similar product but it doesn’t require the use of a remote service and integrates into TFS http://msdn.microsoft.com/en-us/magazine/jj656636.aspx
    http://msdn.microsoft.com/en-us/library/hh973129.aspx

    Apparently it can create work items if a sufficient number of unhandled exceptions occur (and you can modify this behavior). It seems to be quite under the radar.

    The barrier of entry is higher given the TFS integration vs a rest service, though. I think ELMAH is better than both at the end of the day. Graphs are nice but you have to investigate the exception at the end of the day anyway, no?

  6. Daniel LangNo Gravatar says:

    I guess I am a potential customer because I’m running multiple ASP.NET application where I absolutely do care when exceptions occur. Right now, I’m using ELMAH to catch errors, store them in XML files or SQL and let ELMAH send me notifications to my email address. Setting this up takes only a few minutes because the ELMAH NuGet package does everything for you.

    What benefit would I get from using Raygun (except a fresher UI)?

  7. Phillip Haydon (@philliphaydon)No Gravatar says:

    @Daniel – From my point of view, having used ELMAH for years and now using Raygun, it’s still too much setup.

    If I wanna use SQL Server I still have to manually set all that up, email notifications ended up spamming me so I ended up using another email, but then ended up not checking the email, and ended up just giving up on the email notifications all together. The UI is kind of clunky and doesn’t offer me much information in my opinion.

    I think I noticed the benefits of Raygun within the first week, having it group together exceptions and tell me which exceptions were happening more than others allowed me to focus on fixing them quicker, and once fixed I can tag them as resolved to filter them out. A few exceptions happened from google bots so I put them on Ignore, and within the first week I think I fixed about 20 or so exceptions, my site gets 1-2 every week now that are caused by search engine bots.

    Using ELMAH in a non-web scenario is next to impossible, but Raygun allows me to use the same logging in my Website (Client side in JavaScript and ServerSide) and my Windows Store App. Using ELMAH I wouldn’t be able to do that at all, well I could but I would have to write a lot of code to do that.

    The UI for Raygun is awesome, the graphs, grouping, filtering, searching, etc all makes the experience worth while that I actually care about exceptions now. I really think it’s something you have to trial on a real world project to truly see the benefits.

  8. Daniel LangNo Gravatar says:

    Thanks Philipp, appreciate your detailed answer. I’ll give it a try and switch over one of my existing projects to see how it works out for me.

  9. Pingback: The Daily Six Pack: March 28, 2013 | Dirk Strauss

  10. Juan J. ChiwNo Gravatar says:

    I’ve been using graylog2 like 2 years ago, there were no raygun at that time and we use gelf4net an appender for log4net.

  11. Mark ChipmanNo Gravatar says:

    Filip, you might want to have a look at Elmahr (Elmah + SignalR)… it also creates a dashboard for monitoring one or more of your apps.

    Regards,

    Mark Chipman

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>