StackExchange.Exceptional: ELMAH on steroids
Logging is a really important system if you care about your users. Not only should it give you errors details, but also notify you that something is wrong before users start complaining or submitting bug reports.
There are probably dozens of logging solution, and I’m sure there are hundreds thousands of self-written loggers on various projects. But I wouldn’t recommend writing your own logging since
you probably won’t be able to do it right the first time (and the second, and the third etc). It’s better to use existing solution, like ELMAH (Scot Hanselman’s blog post about it)
What is ELMAH?
ELMAH is an acronym: Error Logging Modules and Handlers. So it is an ASP.NET HTTP module that handles all unhandled exceptions and stores them for you. It also gives you ability to review what happened in your application from the application itself.
As you can see, ELMAH subscribes to
HttpApplication.Error event, and gets the last error in the
OnError method :
The cool thing about ELMAH is that you actually don’t need to write any code to use it. In fact, you can add it to already deployed and working application.
ErrorLogModule to your
web.config, and it will just work (you also need to configure ELMAH in corresponding config section).
You can also manually log exceptions using
We got the main idea about logging exceptions, now let’s find out how to investigate logged exception.
Just navigate to
http://yoursite/elmah.axd, and if you have
ErrorLogPageFactory handler added to your
web.config you will see the following:
You can click on individual exception to get more details:
Pretty handy, isn’t it? It is, especially if you also want to send emails on each exception, filter unwanted exceptions etc. Yes, ELMAH supports this.
StackExchange strikes back
StackExchange team used to use ELMAH (a custom port). At some point they decided to write their own ELMAH with some improvements.
So StackExchange.Exceptional was born. It essentially works the same way as ELMAH (also has ASP.NET Module which is added to your application). Let’s just add the top image again here, this is how StackExchange.Exceptional looks like:
But it also has some improvements, which I find very useful.
Exceptions duplicates count
StackExchange.Exceptional doesn’t log exceptions as a new log entry if a similar exception occurred some time ago. Instead, it just increments duplicates count on original exception. How does it know two exceptions are the same? By comparing exceptions types and stacktraces. This will allow you to find most common exception faster.
You can set
applicationName attribute in
<Exceptional> section in
web.config. This value is written to the DB and allows you to use the same table for different applications.
For example, you can store exceptions from user site, admin site, workers, services, api projects in the same place and easily filter them when you need it.
There is another tool from StackExchange which seamlessly integrates with StackExchange.Exceptional. It is an open source ASP.NET MVC application called “Opserver”. Opserver is web UI for monitoring things StackExchange uses like MS SQL, Redis, ElasticSearch etc. A natural use case for Opserver is viewing exceptions from StackExchange.Exceptional, and it supports it. Moreover, it supports search and filtering, which makes it extremely useful.
So let’s setup Opserver so that we can easily investigate issues with such applications:
- User site
- Admin site
- External API project
Each application has corresponding
applicationName attribute, so, for example, User site will have
<Exceptional applicationName='User site'> and so on. Each application uses the same db for exception
To configure Opserver we need to:
- Clone Opserver from https://github.com/opserver/Opserver.git
SecuritySettings.configappropriately. For our demo purposes let’s set
<SecuritySettings provider="alladmin" />:
- Launch Opserver, use a random pair of login\pass when asked (remember we set
alladmin?), and you should get this:
You can filter exceptions by clicking on app name and search exceptions.
At this point, I don’t see any reasons why you should use ELMAH instead of StackExchange.Exceptional. Essentially it is ELMAH + additional features + you have opserver. Anyway, you choose.