This article has been originally written several months ago, but it's been substantially reviewed and integrated after ElmahR's 1.0.0 release.
I've been listening and reading about SignalR since the beginning of the project, at the same time I'm an ELMAH user since a while and I have had the pleasure to share my working hours and my lunches with its author. At some point I had this idea to join these two libraries to offer real time and interactive experience to the logging capabilities that ELMAH offers, with a special focus on the fact that a dashboard should aggregate multiple applications's error feed in one place. ELMAH + SignalR = ElmahR.
ElmahR is a web dashboard where you can aggregate several monitored applications; adding them to ElmahR configuration will enable them to post error events, which will show themselves on all the connected client dashboards in real-time. ElmahR is about error logging in real-time, and to do that it's based on ELMAH for the error logging part and on SignalR for the real-time notification piece.
The integration with ELMAH is not based on binary dependencies, but on data exchange. ELMAH already defines a set of fields and collections which describe an error, and ElmahR borrows this data structure and builds its logics on top of it. This approach makes ElmahR virtually independent from ELMAH: whoever is able to craft an error description matching the data format from ELMAH can send error events to ElmahR and have them published. It has not to be an ASP.NET application, it could be a desktop client, a mobile app, it could even be developed on a non-.NET platform, as long as it can post data over HTTP. Nevertheless the most convenient way to use ElmahR is to enable ELMAH on the ASP.NET web applications you have to monitor, and configure them to post errors to ElmahR, this way you'll leverage all the great logging features that ELMAH already has. To do that you will need the new ErrorPostModule, which I wrote myself and is not part of official ELMAH but it belongs to the ElmahR.Elmah component of ElmahR.
Let's suppose you already have ELMAH correctly configured on the application you want to monitor, all you have to do to connect it to an instance of a dashboard is to configure ErrorPostModule appropriately:
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorPost" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<errorLog type="Elmah.MemoryErrorLog, Elmah" />
<validation validateIntegratedModeConfiguration="false" />
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorPost" type="ElmahR.Elmah.ErrorPostModule, ElmahR.Elmah"/>
<compilation targetFramework="4.0" />
Just as simple as that. There are 2 relevant parts:
- where the
errorPost section is configured with the
targetUrl and the
where the new http module is added in the standard ASP.NET section modules in
targetUrl: address where
posterror.axd can be found;
posterror.axd is the ElmahR endpoint you have to target in order to HTTP POST errors, it understands the ELMAH data format and it's able to receive errors and treat them properly
sourceId: key you specify to identify the application, it will be used by ElmahR to match errors coming from this source to the right feed on the dashboard
Please note that ErrorPostModule has no dependency at all on SignalR, it's just doing a plain old HTTP POST following some conventions about how to pack data. If you want you can configure things to have the same application running both the monitoring and monitored roles (although that's not recommended for several reasons, that particular scenario is handles with another internal module called ErrorTrapModule which avoids the HTTP POST). You will find more info about how to configure a source application, and about how to wire it to a specific dashboard, reading the docs available on the project site on Bitbucket.
Let's move to analyze the SignalR side of the project, that's what I did:
- I wrote a SignalR hub which easily enables the client-server communication
- I introduced a
.axd handler where errors are posted and unpacked thanks to the same conventions used on the ELMAH side
- I wrote a dashboard page where you can see the errors popping up in real time, thanks to the
- I added some optional features to persist received errors on durable devices in order to enable the application to notify new clients about older exceptions
When an error arrives to ElmahR after the post steps described earlier, the server side uses SignalR to redistribute it to all the connected clients. When SignalR does its magic, errors arrive to the clients as JSON structures which still resemble the ELMAH data format. One of the goals I had here was to reach is a good level of separation of concerns and modularity, which would more easily enable a seamless integration of new modules. That's why the "low level" code which handles SignalR notifications is made "overridable" in order to enable you to hook more advanced client side functionalities and user experiences on top of "core" broadcast features. There are more areas where SignalR has been helpful, things like server-side filtering, smart history persistence for new or reconnecting clients, and even client side plugins delivery, are features made available to the dashboard thanks to great SignalR features like hubs, persistent connections or groups.
As soon as ElmahR started growing as a project, improvements on the UI became necessary. The amount of information started getting big, and potential UI scalability problems became clear. Finally we had time to concentrate on the visual aspects of the dashboard, trying to come up with something more reactive, better at bringing the right information and at scaling along with the number of monitored applications. This last issue has been worrying us the most, it's not easy to accommodate the potentially quite big volume of info that ElmahR handles.
We let ourselves be inspired by Twitter web site user experience, and we took advantage of the Twitter bootstrap framework to build a responsive layout. It is a very interesting framework, it allowed us to greatly improve how the dashboard looks like, and now we have better support of different form factors and browsers.
Twitter bootstrap is quite simple, but it can also help deliver sophisticated UIs, and in order to enable that it can get pretty complex. We cannot really say we understood everything of it, but we also wanted to deliver soon, so we found a quite good and quick compromise analyzing a Bootstrap sample application and modifying it to our needs. This will probably be one of the areas where enhancements and updates will be produced in the near future.
Should you try the demo web site, you will notice that we have a responsive layout, normally composed of 3 columns which collapse to just 1 when the available width goes below a certain limit, as it happens on a phone.
The first columns is composed by summary boxes. The first box shows overall info like the total number of errors, the latest error type and the name of the application which raised it. The remaining boxes are similar, but specific for each monitored application. Those app-specific boxes are sortable by dragging and dropping them, they can be expanded to show the errors belonging to each of them, and the relative error feeds can be paused or resumed. From there you will also be able to trigger test exception on source applications thanks to the skull button, just to check if everything is wired correctly.
The second column is a global feed where all the errors are stacked up, the newest ones going on the top, this column let the user know about the latest errors occurred at a glance. Each error is expandable to see full details in a popup, which is disabled when the dashboard runs on small form factors (we're still looking for a better way to show details on those kind of devices).
The third column is intended to host additional pieces, so far we built 2 statistical 'plugins' which should be considered samples about how to build such extensions using ElmahR extensibility features.
As already mentioned, ElmahR has some extensibility features, which come from the fact that the structure of the project has been made more and more modular during time. Now ElmahR dashboard is made of several pieces:
- ElmahR.Core: this is where most of the logic lives, from error handling to broadcasting, from default persistence to pluggability systems; a simplified real-time log stream is delivered at this level
- ElmahR.Modules.Dashboard: the "true" real time interactive dashboard is delivered by this module
- ElmahR.IoC.*: ElmahR has an embedded dependency injection mechanism thanks to TinyIoC, but it lets you override it in order to integrate with your favorite IoC picking an existing module or building your own (so far only NInject has a proper module available)
- ElmahR.Persistence.*: ElmahR's default persistence mechanism stores error in memory, but this subsystem comes from a module and can be replaced in case you need to store errors onto a durable system. We have modules for EntityFramework in order to support and relational database, but also for MongoDB in case you need to support it and, as for the IoC container, you could easily build your own modules to support other scenarios
This modularity has some positive impact on the client side
Thanks to the above mentioned modularity, it's been possible to find a ways to distribute both dashboard instances and the ElmahR.Elmah module through Nuget packages, which you will find here.
During the last few months more features have been added, the most notable being:
- Dashboard-related Nuget packages
- ElmahR.Elmah Nuget package
- Test exceptions launcher
- ElmahR as a source of errors for itself
- Low level logging
- Historical errors statistics and clean up
- MongoDB persistence
- Error post encryption
- Modular structure
- Plugins system
- CSS + JS bundling and minification
- IoC container support
Please refer to the project repository for more detailed documentation.
Project nature and goals
It's been real fun to work on it because it allowed me to try a lot of great stuff from out there, like:
- ELMAH, of course, writing a new module for it
- SignalR, really amazing library
- Knockout for doing MVVM in the browser, 'magical'
- Raphaël to build like graphs in the browser
- Underscore.js to 'compose' statistics client-side 'à la LINQ'
- jQuery, of course
- Mercurial on Google Code for the ELMAH Sandbox, and on Bitbucket for the official ElmahR home
- AppHarbor for hosting the live demo, it's a fantastic platform, deploying .NET apps is never been so easy!
- Trello for light 'project management'
- ...and many more!
I admit I'd like to have ElmahR evolve in a way that people would consider it a good sample app for libraries like ELMAH, SignalR or Knockout. I cannot say if this goal will ever be reached, if some of you guys out there want to help me in this effort (even simple advices or suggestions would be very welcomed) I'd be glad to try with you!
- follow the evolution of the project here
- check the code and read the docs here
- see a live demo here
- get the Nuget packages here
- 2013-03-XX: Version 1.0.0 finally available! Modularity and Nuget
packages among other improvements
- 2012-11-11: Version 0.9.7, error post encryption available
- 2012-10-24: Version 0.9.6, async persistence + MongoDB persistor
- 2012-09-20: Version 0.9.4, errors statistics and cleanup
- 2012-07-18: I gave a talk about ElmahR at aspConf, a recording of the talk is available on
- 2012-07-15: Version 0.8.8, plugins system, plus various refinements.
- 2012-06-01: Version 0.7.2, persistence user preferences like application feeds status.
- 2012-05-21: Version 0.7.0, new persistence module writing on database, and retrieving historical errors from there.
- 2012-05-17: Version 0.6.5, enabling user to ask for older errors.
- 2012-05-16: Version 0.6.1, project now uses SignalR 0.5.
- 2012-05-04: Project is currently at version 0.6.