Foundatio Featured on .NET Blog + Version 4.0 Release!

Foundatio 4.0 releaseWe've continued to focus some of our attention on our pluggable app foundation block solution, Foundatio, and last week it got some attention from the Microsoft .NET Blog as well!

Foundatio featured as Project of the Week on .NET Blog

We've also released V4.0, which has some new implementations, API changes, and, of course, bug fixes.

Check out the details, below.

Foundatio 4.0 Release Notes #

Implementations #

We've got a few new implementations with this release, including Amazon S3 storage, Azure Service Bus queue (thanks @jamie94bc!), and Redis metrics client. Users should find those helpful.


The APIs have been drastically simplified for ease of use and straightforwardness, which should allow for easier creation of new implementations and consumption of existing ones.

Once example of this simplification is that we've paired down jobs to having only one lock, instead of four.

Logging has also seen huge improvements to make sure we are aligned with future API implementations, etc.

Bugs #

More tests have been added since the previous release, and we've fixed a few major bugs as well.

  • Deadlocks were occurring in a few areas, which is now remedied.
  • Dropped connections are now automatically healed, while previously we were seeing some issues.
  • Cached reference types can no longer be updated.

Upgrading to Foundatio 4.0 #

If you're already using Foundatio, simply updated your NuGet package. If you're new and want to check it out, snag Foundatio over on GitHub.

And, as always, we're here to answer any questions or take any feedback you might have to offer!

Exceptionless V3.3.0 Release - Now with Even More Awesome

Exceptionless 3.3.0 Release Notes

We always work hard to keep improving Exceptionless, and this release is no different!

Since the last release, we've put a lot of time into making the filtering and searching more user friendly and intuitive, improving the reliability of jobs, and of course fixing any bugs that you guys (or Exceptionless) have been able to find.

Let's see what we've got going on, shall we?

What's Goin On? #

For starters, as mentioned above, we relocated the search bar to exist on the top level of the UI, and the date picker filter now shows the current choice on the top level. Both icons were replaced, and we really think it's much more intuitive and efficient. You can read more and see examples over on the dedicated blog post we did last week.

New Stats API #

You can now get a timeline or numbers for a comma delimited list of fields using the new stats API, which is pretty cool.

Session Management #

Session management has been drastically improved by doing a few different things. For instance, inactive sessions are now closed faster, but they can be opened again if need be. We hid heartbeat events by default, too, and you can now specify manual sessions for desktop-based apps.

Manual Stacking #

We introduced custom event stacking a few weeks ago, and @adamzolotarev has added the ability to specify a manual stacking key on the client side with this release. Thanks Adam!

Discard events created from bots #

A default list of bot wild card exclusions is now automatically set on new projects, so if you're upgrading, you now have the ability to run a maintenance job via the admin controller to set a default bot list. All events with user agents matching these wild cards will then be discarded on the client side.

Bugfixes! #

  • Marking stacks as fixed or hidden was causing some significant slow down and sometimes wouldn't work at all. This has been remedied!
  • Redis connection failures and lock timeouts were sometimes causing jobs to stop working or fail. We dug through and found what was causing that and fixed it as well.
  • When the geo field contained a localized number, sometimes events were not being processed. This localization issue has been solved.
  • And last but not least (well, maybe least), a seralization bug has been fixed that would cause query strings, cookies, and other extended data items to be transformed to lowercase and underscored.

Time to Upgrade #

Well, only if you're a self hoster. Everyone else will experience all of these awesome improvements and bug fixes the next time they log in. If you are a self hoster, please review the Self Hosting Docs for info regarding upgrading your current Exceptionless install. Naturally, if you have any questions please let us know and we will get you taken care of.

In Conclusion #

You can find a complete comparison changelog over on GitHub, where you can also submit any issues, etc if you run across anything. Please also let us know what you think of the changes by commenting below, pinging us on social media, or simply sending Blake a glitter bomb (site/link not endorsed in any way, lol - first one I found!).

Filter Improvements to the Exceptionless Single Page App

SPA filter search solutionsIt's been a while since we introduced filtering and searching when we launched Exceptionless V2.0, so we decided recently that we wanted to take the feedback we've received and do a round of improvements to it.

You may have already noticed the changes, but if not then the next time you log in you will see that the top bar has changed, giving you much quicker access to filtering and more upfront information.

Filter Changes to the Desktop View #

For the primary desktop view, we removed the magnifying glass icon in the top bar and simply filled the rest the bar with the filter (search) input box. This eliminates a click to get to the filtering system, and keeps it front and center at all times.

One important note here is that if you want to show events that have been marked as fixed or hidden, you have to explicitly specify those filters, whereas previously those options were check boxes. So, you can use hidden:false or hidden:true, and fixed:true or fixed:false to view those events. Naturally, the default is false for both, showing events that have not been hidden or fixed. This means that in order to see both hidden and un-hidden events, you would need to use hidden:false OR hidden:true. Likewise, for fixed, you would need to use fixed:true OR fixed:false.

You'll notice that the date/time filter has changed as well. Instead of an icon, we now display the current time frame being viewed, once again saving you a click and keeping things in front of you.

As always, the filter still applies to the chosen time frame only.

Before #



After #



Mobile Changes & Functionality #

We also changed the user interface for smaller screens.

Instead of the icons at the top of the screen, the time frame selector is now a major menu item in the mobile menu and displays the current selection with the filter/search field directly below it.

This setup should allow users to filter and find the events they seek much quicker on mobile.

Before #


After #


Pretty Cool, Yeah? #

We think it's a pretty nice improvement. We got feedback from several users and think making everything visible at the top level of the user interface is an important change that saves time and keeps you informed.

If you've got any additional feedback, please don't hesitate to let us know. We are always looking for ways to improve, and we use Exceptionless every day too, so we are always interested in saving ourselves time and making things easier on our end!

Simple App Deployment with Azure Continuous Deployment and GitHub

simple app deploymentWe’ve learned a lot about simple app deployment since we first started Exceptionless. We initially went with what everyone else was doing (Octopus Deploy), but over time we thought we could greatly simplify and automate it, letting us focus on what matters, improving the product!

Through a lot of testing and iterations of our deployment process, we think we finally nailed it.

As such, we’d like to share with the community how we use Microsoft Azure Continuous Deployment and GitHub for **awesomely simple deployments. **And, how you can too. See the details of implementing this deploy workflow later in the article, below.

Exceptionless Deployment History #

In the Beginning #

When we first started Exceptionless, we deployed it as a monolithic application, meaning the server and UI were one piece, or app. We used Octopus Deploy to deploy to a single IIS machine, which involved setting up a website and server for the Octopus Deploy service and configuring build agents, on each server we deployed to, that could deploy build artifacts.

The Move to Azure #

After a year or so of managing Exceptionless on colocation boxes in a Dallas data center, we realized that we didn’t want to manage hardware anymore and we could scale easier on a managed service like Azure. So, we moved to Azure, where we had to set up a VM just to manage deployments with Octopus Deploy. There were also issues that we ran into with deploying to Azure WebSitThis was annoying, since every time we wanted to do a release we had to log in and tell the system to deploy to production.

We knew there had to be a better way.

Two Steps Forward... #

Soon, we decided to split the UI and Server apps so we could deploy and work on them independently. This also meant they could scale independently and one change to either wouldn’t cause the whole site to go down when deploying. Splitting the two helped a lot, but it added more work as we now had to manage two Octopus Deploy projects. So, we started looking at the Continuous Deployment in Azure.

Aha! Eureka! Solution Time! #

We researched further and found out that if we used Git Flow as a development workflow, we could ditch Octopus Deploy completely, remove that dependency, and just use Git push to manage our deployments.

With Git Flow, you do all your work in feature branches and the master branch is always stable. This allows us to set up GitHub deployment on the master and deploy to Azure automatically, with no work required! So anytime we push to the GitHub master branch, it automatically deploys to production on Azure. That simple!

Here is the BASIC workflow:
  1. We create a new feature branch, then work on that branch until it is completed and tested. Testing is done on the website that is currently pointed to the feature branch, which is separate from production.
  2. When we commit to any branch, our continuous integration (CI) server picks up the changes via a GitHub webhook, pulls them down, then builds the project.
  3. We then take all of the build artifacts and push them to a second GitHub repository using the same branch that the code was pushed to (for example, the master branch). This allows you to see exactly what artifacts change between releases (stateless too) and different branches.
  4. Those changes are then automatically pushed via Azure Git Deploy.
  5. Profit!

This is very slick! Since we push artifacts to the same branch they were built onto a build repository. We can then set up different environments that get auto deployed when we push to that branch. For example: When we are working on a feature, we commit to our branch. We can then set up a new website in Azure that pulls from the build server’s Git artifacts branch for that feature. This allows us to test and automate environments!

Detailed Continuous Deployment Setup #

Here are the details on our solution for simple app deployment using GitHub and Azure.

1. Use AppVeyor to build the app. #

2. Store build artifacts in a separate GitHub artifacts repository. #

This works really well because you can see the entire history of your build artifacts and browse their contents. Plus, GitHub hosts it for free!

We found that we could that GitHub could understand and parse into different links. We can click on the "Commit:" part of the message to link to the actual commit that is building to see exactly has changed.

github build history artifacts

We can then click on the build to see what artifacts changed.

gitHub build history details

Another great thing about using Git to store your artifacts is that you can easily clone the artifacts to your local machine to see the exact files that are being used in a specific environment.

The artifacts repository has branches to match the branches of our code repo so we have separate build artifacts for each branch. This also means that we can just merge the feature into master when we are done and that will cause the production website that is pointed to our master repository to automatically get updated. So, it’s as simple as merge your branch to master to promote a build to production.

merge-branch-master promote build production

One issue with this approach is that the repo can get large because we are storing binary files that change on every build. We are looking into using Git Large File Support to fix this issue.

3. Automate pushing of artifacts to a secondary GitHub repository. #

For our .NET application, Exceptionless, we invoke a PowerShell script on post build to clone and commit the changes to the Git artifacts repository.

  1. Our first step is to clone the existing build artifacts repo to an artifacts directory.
  2. Next, we change to the same branch that we are currently building, if it doesn’t exist we create it.
  3. Then, we remove all existing files in the artifacts folder. This ensures we don’t have any conflicts and we can see exactly what was added or removed.
  4. Next, we copy our build artifacts into the artifacts folder. This allows us fine grained control over our artifacts.
  5. Next, we try to commit all artifacts to the artifacts repository. If there were no changes between the last build, then we exit.
  6. Next, we push the artifacts to our GitHub artifacts repository, which will then trigger Azure Continuous Deployment to pick up the changes.
  7. Finally, we create tag the artifacts repository which points to the specific GitHub commit we are building in our main repository.

For our static Angular JavaScript app (UI), we invoke a Grunt publish task from our post build event. The publish task called into a gh-pages task that publishes our built dist folder to the GitHub artifacts repository automatically.

4. Point Azure Continuous Deployment to the Artifacts Repository #

It will see when new artifact commits happen and automatically deploy the changes.

azure sees new artifact commit and deploys

Azure Continuous Deployment is another Git repository that we can easily view to see the history of deployments to each of our sites. It also allows us to easily roll back to previous versions.

5. Use Environment Variables to Override Config Settings Per Environment #

Azure Websites makes this very easy.

azure override config settings environment variables

No production settings are stored in source control or artifacts repository.

For our ASP.NET application, our settings class will look up named settings in the following order:

  1. environment variables
  2. local config.json file
  3. app settings

It will then fall back to a default value if no explicit settings are found.

Configuring our static Angular JavaScript app is a bit more work since it can't look these settings up dynamically at runtime. So instead we add some code to our deployment process.

  • Azure automatically runs a file after getting the artifacts via git deploy. It’s sole job is to run a node script that rewrites our app.config.js settings with settings defined in environment variables.

Conclusion #

You can create multiple Azure websites (think environments) that use Continuous Deployment and point them to multiple artifact branches to support different environments!

Pro Tip: We created a website for our spa website that’s pre-built and points to your localhost Exceptionless server. This allows us to do work on the server part without setting up or configuring a local instance of our spa app. Development made simple!

We won't lie, it took some work to get here, but the good news is you can do this really easily too. Please feel free to steal our deployment scripts and modify them for your projects. And let us know if you have questions along the way!

Custom Event Stacking in Exceptionless

custom event stacking with exceptionlessSometimes you just need things to be your way.

We get it... your morning coffee, folded towels, and how events stack (group) in your event reporting application should be controllable and customizable.

Well, thanks to a great suggestion by @adamzolotarev, now they are! Well, the events, at least.

Why Custom Event Stacking? #

We do our best to group your events into relevant and smartly-named stacks, but there are cases where you may want to specifically name a stack and attribute certain events to it for organization, reporting, troubleshooting, or other reasons.

To facilitate this need, we created SetManualStackingKey, which both .NET and JavaScript client users can set.

How Do I Create Custom Event Stacks? #

Adding your own custom stacking to events in Exceptionless is super easy. Below are examples for both .NET and JavaScript.

In these examples, we are using setManualStackingKey and naming the custom stack "MyCustomStackingKey".

So, any events you use the below for will be a part of the custom stack, and all other events, exceptiones, logs, feature usages, etc will still be stacked automatically, like normal, by the app.

.NET Custom Event Stack Example #

try {
throw new ApplicationException("Unable to create order from quote.");
} catch (Exception ex) {

Alternatively, you can set the stacking directly on an event (e.g., inside a plugin).


JavaScript Custom Event Stack Example #

var client = exceptionless.ExceptionlessClient.default;
// Node.Js
// var client = require('exceptionless').ExceptionlessClient.default;

try {
throw new Error('Unable to create order from quote.');
} catch (error) {

How Do We Stack Up? #

We're always interested in what you think of Exceptionless' features and functionality, so let us know if you find custom stacking useful, need help implementing it, or just want to chat over on GitHub.

Thanks for reading!

New Releases: Exceptionless 3.2.1, .NET Client 3.3.6, JavaScript Client 1.3.2, UI 2.3.1

![Exceptionless error logging](/assets/img/news/blog-header-image-3.2.1.jpg)

Since the last major release cycle, we've made several minor releases, including Exceptionless 3.2.1, Exceptionless.NET 3.3.5, and Exceptionless.UI 2.3.1.

Lets take a look at some of the highlights, and you can check out the full release notes on each at the provided links, below.

Exceptionless 3.2.1 #

We fixed a few minor bugs made a few improvements to the main platform. Check them out!

  • Free accounts can now look up events by reference ID (bug).
  • Improvements to posting events via GET.
  • Items can now be added and removed from project data (bug).
  • Users can log directly in to an existing account if they attempt to sign up with the same credentials now, rather than getting an error.
  • @VikzSharma fixed the "too many bad attempts" lockout feature. Thanks!
  • There is also a once-an-hour limit on user signups and email address changes thanks to @VikzSharma.

Upgrading: Only self-hosters need to worry about upgrading - see details on the full release notes.

Exceptionless.NET 3.3.3 - 3.3.6 #

We've pushed out several minor releases of the .NET client in the last few weeks. I'll cover the major stuff here, but you can view the full release notes and get the latest source on GitHub.

3.3.6 #

  • An issue causing query string params and cookies to be renamed when dictionary key names were being changed has been fixed.
  • client.Register() now respects your session setting.
  • Manual stacking now uses a model instead of a string, which lets us send a stack title and key value pairs telling the event how to be stacked. More info on the release page.

If you are using manual stacking, this is a required update. See the release page for the latest source.

3.3.5 #

  • New extension methods have been added for events, making it easier to set valid geo coordinates, tags, and more.
  • A few new variables and parameters have been added for session heartbeats and id setting. See release notes for details.
  • @InlineASM fixed an issue for geolocations that have different separators - thanks!

3.3.4 #

  • @ahmettaha added SubmitLog and CreateLog overloads without source parameters. Thanks!
  • ExceptionlessClient.Default.Configuration.UseDebugLogger() only worked in debug mode with client source, so we replaced it with ExceptionlessClient.Default.Configuration.UseInMemoryLogger()
  • The serializer wasn't always being passed through so it could get known event data helper methods, which was causing some silent failures - this has been fixed.

3.3.3 #

  • @adamzolotarev added the ability to take complete control over how an event is stacked (be careful) by adding the ability to do manual stacking by calling EventBuilder.SetManualStackingKey("MyStackingKey")
  • You can now ignore events by user agent bot filter when you call (ExceptionlessClient.Default.Configuration.AddUserAgentBotPatterns("*bot*")) on the client side or edit project settings server side.
  • The default max size limit of RequestInfo has been increased.
  • Extra nesting has been reduced by merging exception.Data properties into the Error.Data dictionary.
  • Bug Fix: AggregatedExceptiones that contain more than one inner exception are no longer discarded.
  • Bug Fix: Machines with a Non-English locale will not process events when SetGeo is used.
  • Bug Fix: ArgumentNullException will no longer be thrown if post data or cookies contain a null key.

Exceptionless.JavaScript 1.3.2 #

  • @frankebersoll contributed by adding support for offline storage, which can be enabled by calling client.config.useLocalStorage(). Thanks!
  • User agent bots can be ignored via a filter now with (`client.config.addUserAgentBotPatterns("bot")) on the client side or via project settings on the server side.
  • @frankebersoll also added support for manual stacking (be careful! grants complete control). See release notes for instructions.
  • The implementation of the angular $stateChangeError has also been improved.

Full release notes

Exceptionless.UI 2.3.1 #

There's nothing major to report with the UI, just a few tweaks.

  • The project settings pages has been reworked by adding the ability to specify user namespaces, and user agents that the clients will ignore. @VikzSharma also fixed an issue where the single page app could be clickjacked - thanks again!

Full release notes and latest release download.

Questions? Let Us Know! #

If you've got any questions about any of the release notes above, please don't hesitate to let us know by commenting below or submitting an issue to the respective GitHub repo, above.

Thanks for checking out our release notes.

Add Reverse Geocoding to Your App

Reverse Geocoding

We recently introduced reverse geocoding into Exceptionless and are now adding features to make full use of it.

What we'd like to do in this blog article is walk any interested developers through the process of adding it to their own app.

We'll talk about the resources and services we're using to pull it off, why we chose them, and give you code snippets for implementation. It's all open source, so we've also included links to all the relevant code in hopes it will make your life easier!

Lets check it out.

What is Reverse Geocoding? #

It’s the process of taking geo coordinates or an IP Address and resolving it to a physical address (E.G., city, county, state/province, country).

Why You Need It #

Reverse Geocoding - User Location

Wouldn’t it be nice if you could provide location services to your users automatically? Maybe help them fill in a shipping form from a zip code or there current location?

With the launch of Exceptionless 2.0 we added a geo property to all events. This allows us to translate valid latitude and longitude coordinates into a physical location. Our goal was to begin capturing the data then and enable different scenarios and uses later. This also allowed us to show end users where their customers events are being submitted from.

What does it cost? #

One of our primary goals with Exceptionless is to be completely open source and easy to use (both in setting up self hosting and using the product). We had to take this into account when picking any library or service, because we want a painless setup and no additional costs for self hosters, all while adding additional value!

Please note that if you love the services we use, you should look into using one of their paid plans or at least promoting them with a positive review, shout out, etc (everyone needs to eat at the end of the day, right?).

After researching many different services, we ended up goin

g with GeoLite2's free, offline, downloadable databases. These databases are free and updated once a month, but if you require a more accurate and up-to-date database they offer a paid subscription. We also use their open source library for interacting with the database in memory.

Automating the GeoIP Database Download #

We use our very own Foundatio Jobs to download the most up-to-date database. Foundatio Jobs allows us to run the job in process or out of process on a schedule in Azure.

Alternatively, you could use the PowerShell script we created for downloading the database.  <a href="" target="_blank">DownloadGeoIPDatabaseJob</a> downloads the database over http and extracts the file contents to disk using Foundatio Storage.

Please feel free to take a look out our job for a complete sample including logging and error handling:

var client = new HttpClient();
var file = await client.GetAsync("", context.CancellationToken);
if (!file.IsSuccessStatusCode)
throw new Exception("Unable to download GeoIP database.");

using (GZipStream decompressionStream = new GZipStream(await file.Content.ReadAsStreamAsync(), CompressionMode.Decompress))
await _storage.SaveFileAsync("GeoLite2-City.mmdb", decompressionStream, context.CancellationToken);

Looking up a Physical Address from an IP Address #

Resolving the geo coordinates into a location

After we automate the database download, the next step involves loading the database in memory using the open source library provided by MaxMind and querying by the IP address. The code below will do very basic IP validation and lookup the records using the API.

private DatabaseReader _database;
public async Task<GeoResult> ResolveIpAsync(string ip, CancellationToken cancellationToken = new CancellationToken()) {
if (String.IsNullOrWhiteSpace(ip) || (!ip.Contains(".") && !ip.Contains(":")))
return null;

var database = await GetDatabaseAsync(cancellationToken);
if (database == null)
return null;

try {
var city = database.City(ip);
if (city?.Location != null) {
return new GeoResult {
Latitude = city.Location.Latitude,
Longitude = city.Location.Longitude,
Country = city.Country.IsoCode,
Level1 = city.MostSpecificSubdivision.IsoCode,
Locality = city.City.Name
} catch (Exception) {
// The result was not found in the database

return null;

private async Task<DatabaseReader> GetDatabaseAsync(CancellationToken cancellationToken) {
if (_database != null)
return _database;

if (!await _storage.ExistsAsync("GeoLite2-City.mmdb")) {
Logger.Warn().Message("No GeoIP database was found.").Write();
return null;

try {
using (var stream = await _storage.GetFileStreamAsync("GeoLite2-City.mmdb", cancellationToken))
_database = new DatabaseReader(stream);
} catch (Exception) {
// Unable to open GeoIP database.

return _database;

Then, just call the ResolveIPAsync method with an IP address to look up the location details.

var location = await ResolveIPAsync("YOUR_IP_ADDRESS_HERE");

Feel free to take a look at <a href="" target="_blank">MaxMindGeoIPService</a> for a complete sample that includes logging, error handling, caching of the results, and IP validation for higher lookup throughput. We’ve spent the time writing tests and optimizing it to ensure its rock solid and works great. So feel free to grab our IGeoIPService interfaces and models and use them in your app.

It’s worth noting that in our app, we use the IP address provided in the event. This could come from a server request or the actual machine's IP address. We also fall back to the API consumer's client IP address.

Looking up a Physical Address from Geo Coordinates #

As stated previously, every event submitted to Exceptionless has a geo property that can be set. If it’s set, we will attempt to look up your location by the geo coordinates using a third party service. We used the open source library, which abstracts the major different third party reverse geocode services into an easy to use API (options are always good!).

After we decided on the library, we evaluated a few API/lookup services based on cost and accuracy. We ended up going with the Google Maps GeoCoding API. They offer 2500 free requests per day and are one of the most used location services in the world.

Next, let’s write the code that will look up our location from a latitude and longitude. You can find our complete example here.

Remember to get your free api key from Google before running the code below.

public async Task<GeoResult> ReverseGeocodeAsync(double latitude, double longitude, CancellationToken cancellationToken = new CancellationToken()) {
var geocoder = new GoogleGeocoder("YOUR_API_KEY");
var addresses = await geocoder.ReverseGeocodeAsync(latitude, longitude, cancellationToken);
var address = addresses.FirstOrDefault();
if (address == null)
return null;

return new GeoResult {
Country = address[GoogleAddressType.Country]?.ShortName,
Level1 = address[GoogleAddressType.AdministrativeAreaLevel1]?.ShortName,
Level2 = address[GoogleAddressType.AdministrativeAreaLevel2]?.ShortName,
Locality = address[GoogleAddressType.Locality]?.ShortName,
Latitude = latitude,
Longitude = longitude

Finally, just call the ReverseGeocodeAsync method with a latitude and longitude to look up the location details.

var location = await ResolveGeocodeAsync(44.5241, -87.9056);

Final Thoughts on Reverse Geocoding #

It took us a bit of work and research initially to get everything working flawlessly for location services. We hope you grab our code off of GitHub to save yourself all that work. Also, it’s worth noting that we use Foundatio Caching to cache the results of location lookups. It drastically increased the performance and cut down on our limited number of requests to rate-limited third party services!

We also queue work items to look up the geo location since that can be an expensive operation. So, please take this into consideration anytime you are interacting with a third party service.

Feedback? Questions? #

Get in touch on GitHub or leave a comment below to let us know your thoughts or questions. We're always open to suggestions and will do what we can to help you out if you're having issues with implementation!

Replacing DIY Exception Logging with Exceptionless - Case Study

referral-rock-logoToday we bring you a case study from the founder of Referral Rock and serial entrepreneur, Joshua Ho.

Referral Rock is a referral platform for small businesses that Josh created after he "... realized small businesses lacked the tools to make a customer referral program work." The app allows businesses to easily and effectively create, implement, and administer a rock-solid referral program to help grow their business.

Exceptionless recently became a part of Referral Rock's exception reporting and logging toolkit, replacing Joshua's home-grown exception logging solutions, and here are his thoughts!


I've always done my own exception logging. Very basic stuff, where I would just log exceptions to my local drive. This gave me a nice place to just look at errors in my ASP.NET code. As with most code, it ended up in production deployments. At one point, I even built some web pages to view the logs remotely. Those little exception logging code snippets also made it into about 3-5 other projects as the years went by. I knew there was software out there that could do this, but I more or less had it solved for myself. **But that changed recently.**

"One huge benefit Exceptionless adds to my business is giving me the ability to provide better customer support."

Enter Exceptionless #

As I've been growing my own SaaS business for referral software, called Referral Rock, I realized there were times my old solution wasn't effectively capturing all the exceptions and I would have to venture into the Event Log to find out what happened. Also, I liked being able to view the production server remotely, but my little web pages got lost somewhere and I wasn't excited about coding them again. Who likes to code the same thing more than once? Not I.

"I could see details on the requests, browser cookies, user identity... all much more than I could see using my old solution."

So that led me to look for other solutions to view my exceptions remotely, which is when I found Exceptionless. With the help of support, I got it up and running fairly quickly. The guys at Exceptionless were very responsive and helpful in getting me setup.

Usage & Evaluation #

Being a startup, I was initially using the free version for about 2 weeks and was blown away. The UI was great and I love the AngularJS based responsiveness. Soon I had a great pulse on my production server. I could see details on the requests, browser cookies, user identity... all much more than I could see using my old solution. Once I had it set up, I started to see the benefits using other types of events in Exceptionless, such as logging. I started adding some logs when I was debugging an issue with a customer, and it worked great.

"With the help of support, I got it up and running fairly quickly. The guys at Exceptionless were very responsive and helpful in getting me setup."

One huge benefit Exceptionless adds to my business is giving me the ability to provide better customer support. Not only do I know when errors are happening, but also who is seeing them. This allows me to have an opportunity to reach out to that specific customer, once the issue is fixed, and say something like "I saw you had and error when you did XYZ, I wanted to let you know it is fixed now so you can try it again". Taking opportunities to provide that level of service has helped my business.

We are now running a paid version of Exceptionless with multiple projects and I look forward to adding more logs and playing with other features to give me even greater visibility into my web app. Thanks guys!

- Joshua Ho // Founder, Referral Rock

No - Thank You, Josh! #

We love to see people enjoying Exceptionless - it's our baby, and we've put a lot of blood, sweat, and tears (I blame Blake) into it. Keep rocking it with Referral Rock!

Track and View User Session Data - New Exceptionless Feature!

app user session logging

To many, this feature may be the missing piece... that connection you've always wanted to make between users, bugs, exceptions, app events, etc. I'm talking about, of course, user session tracking!

That's right, you can now use Exceptionless to track users as they use your app, which of course will come in super handy when you want to know exactly what they did to stumble upon or cause an error or trigger an event.

Continue reading to learn more about sessions and how you can enable them for your apps.

Session Overview #

First, you must have a paid (premium) Exceptionless plan to report on sessions if you are hosting with us. This is mainly because of the added resource requirements the feature puts on our infrastructure. We think it's definitely worth it, though!

Sessions can be searched/filtered like all other events - they are just an event type like exceptions or logs.

What's in a User Session Event? #

Each user session records how long they were active and what they did. For instance, the average user session on the first week we monitored it using the feature was two hours.

With that, each user session event has a "Session Events" tab that displays all the relevant events that occurred during that session and allows you to see exactly what that user did. This is especially helpful, of course, if that session lead to an exception or noteworthy event in your app.

![App User Session Reporting](/assets/img/sessions-event-tab-user-footsteps-300x142.jpg)

All unique data that remains constant throughout the user session is also stored in the event, such as browser and environment information.

![app user session unique data](/assets/img/sessions-unique-user-data-300x155.jpg)

Sounds Good. How do I Set it Up?

sessions-dashboard-nav First, you'll need to update to the latest client versions to enable sessions, then you'll have to follow the below steps to begin tracking them. Once you've got that set up, visit the new Sessions section under the Reports option on your main dashboard, or navigate directly to If you are self hosting, make sure you update to Exceptionless 3.2 first.

Turning On Session Tracking #

For Exceptionless to track a user for your app, you need to send a user identity with each event. To do so, you need to set the default user identity via the following client methods:

using Exceptionless;
ExceptionlessClient.Default.Configuration.SetUserIdentity("UNIQUE_ID_OR_EMAIL_ADDRESS", "Display Name");
exceptionless.ExceptionlessClient.default.config.setUserIdentity('UNIQUE_ID_OR_EMAIL_ADDRESS', 'Display Name');

Once the user is set on the config object, it will be applied to all future events.

Please Note: In WinForms and WPF applications, a plugin will automatically set the default user to the **Environment.UserName** if the default user hasn't been already set. Likewise, if you are in a web environment, we will set the default user to the request principal's identity if the default user hasn't already been set.

If you are using WinForms, WPF, or a Browser App, you can enable sessions by calling the EnableSessions extension method.

using Exceptionless;

How do Sessions get Created? #

Sessions are created in two different ways. Either the client can send a session start event, or we can create it automatically on the server side when an event is processed.

We have a server-side plugin that runs as part of our pipeline process for every event - its sole purpose is to manage sessions by using a hash on the user's identity as a lookup for the session id.

If the session doesnt' exist or the current event is a session event type, a new session id will be created. If we receive a sessionend event, we close that session and update the end time on the sessionstart event.

We also have a CloseInactiveSessionsJob event that runs every few minutes to close sessions that haven't been updated in a set period of time. This allows you to efficiently show who is online and offline during a time window.

How do I Enable Near Real-Time Online/Offline Then? #

We do this by default in our JavaScript, WinForms, and WPF clients when you call the UseSessions() method.

In the background, we send a heartbeat event every 30 seconds if no other events have been sent in the last 30 seconds.

You can disable this heartbeat from being sent by passing false as an argument to the UseSessions() method.

The WinForms and WPF clients will also send a SessionEnd event when the process exits.

Can I Manually Send SessionStart, SessionEnd, and heartbeat Events? #

Sure! You can send these events manually via our client API to start, update, or end a session. Please remember, though, that a user identity must be set.

C# #

using Exceptionless;

JavaScript #



Tell Us What You Think #

As always, please send us your feedback. You can post it here in the comments or submit a GitHub Issue and we will get back to you as soon as possible! We're always looking for contributors, as well, so don't be afraid to jump in and be the hero the code needs. Contributors get Exceptionless perks!

New Releases for ALL the Codes! Exceptionless 3.2

Exceptionless 3.2 HighlightsThat's right folks - we've gone and released Exceptionless 3.2, which includes releases for Exceptionless.NET, Exceptionless.JavaScript, and Exceptionless.UI! Awe yeah.

We're kind of excited, in case you couldn't tell. Big stuff in here, like session tracking (#BOOM), licensing changes (less confusion - it's a good thing), and posting via HTTP GET (such easy, much wow)!

Lets get into some of the details...

Exceptionless 3.2.0 #


Sessions! #

Track and automatically manage user sessions for much more visibility into their user experience, how they interact with your app, and, of course, any errors or events that occur related to that user. This answers the age-old question, "What the hell was this guy doing when stuff blew up!?"

Check out the User Sessions post for more details and instructions!

Exceptionless Event Sessions


Now it's even easier to integrate with Exceptionless from any environment, because you can post event or meta data via HTTP GET! More info coming soon (blog post).

License Change #

The server and all Exceptionless projects are now using the Apache License, so there should be much less confusion on how things are licensed moving forward. Boring stuff, we know... but important.

User Location #

User locations are now resolved from geographic coordinates or the IP address. We look at the geo property for coordinates or an IP, then we inspect the IP. If no IP or geo coordinates present themsevles, we fall back to the client IP that the event was submitted from.

More Speed Improvements #

As always, we keep speed improvements in mind with each release. With 3.2, we've been able to make more massive improvements in processing time for events (over 250% per 1000 events!) and further reduce app startup times and elastic query execution times. #alwaysoptimizing!

Hourly Throttling #

The hourly event-throttling threshold has been increased from 5x to 10x the plan limit. The way we calculate it is by taking the plan limit and dividing it by the hours in the month, then multiplying it by 10.

Signup Experience #

The signup experience has been improved when inviting users, as well. Thanks @mcquaiga and @theit8514 for your contribution!

Upgrading (Self Hosters) #

Self hoster? Need to upgrade? The latest code can be downloaded from the release page. All other users: No action required.

Exceptionless.UI 2.3.0 #

User experience was the primary focus of this UI release, along with the new sessions feature. More details below, including other improvements and a few bug fix details.

Adding a New Project #

When adding a new project, users will now have a much better experience, and we added a JavaScript configuration section for JS projects. Check it out!

Reference id Lookup #

Support for looking up reference ids was added, so you can now navigate to /event/by-ref/YOUR_REFERENCE_ID to look up an event.

Other Improvements #

  • Better messages and a loading mask has been added to data grids to improve user experience when filtering and loading data.
  • Escaping of strack traces containing HTML or CSS has also been improved.
  • You can now sort extended data items alphabetically.
  • The request and environment info tabs for events now show additional extended data.

Bug Fixes #

  • You can now create an organization or project that ends with a period or whitespace.
  • Sometimes an incorrect time range would be set when users used the history chart/graph to select a period of time to drill down to.

Check out the Exceptionless.UI Changelog for all the code changes (87 files / 75 commits).

Exceptionless.NET 3.3.2 #

Users on desktop applications can now opt-in to sessions by setting a default user and calling the below:


Also, module info was not being included in some error reports, which was incorrect. That has now been fixed.

The full change log can be viewed on GitHub.

Exceptionless.JavaScript 1.3.1 #

Besides integrating with the above, the only major change in the JavaScript client, like the .NET client, was that users can now op-in to sessions. To do so, set a default user and call the below:


Check out the full change log for all the dirty details.