Global Exception Handling / Crash Reporting in Adobe AIR – Partially Solved?

EDIT: Jan 24th, 5:18pm (GMT+1): I am late to add this edit, but much of this post is now obsolete. Adob added Global Exception Handling to AIR 2.0. As far as I know, you won’t be able to get a stack trace if you’re not running in debug mode, and that’s a bummer, but it’s great to be able to catch unhandled exceptions now!

——

As I’ve been developing YNAB 3, I’ve been pulling my hair out to figure out a way to add crash reporting to our application. YNAB Pro, our popular C# app has it, and it’s saved us so many times I can’t even tell you! Our bug reporting system has a log of every crash we’ve ever had in the field, complete with a stack trace and user comments. I’m proud to say that we don’t get many, but when we do, it’s trivial to write back and explain how they can fix it.

Adobe doesn’t think this is important

Coming from the C# world, I thought it would be easy: Just put a try/catch around the main block, and then catch unhandled exceptions, pop up a dialog, and be done! Well, amazingly, you can’t catch unhandled exceptions in Flex/AIR. Yeah, you read that right. You can’t. The #1 voted on bug in their Flex database, with 415 votes as of now, is (to paraphrase) “Please add global exception handling“. Coming in at 160 votes is, to paraphrase again, “Please oh please add global exception handling!“. There seems to be a lot of silence from Adobe on these issues. They’re not prioritized high, and no one ever really comments on those bugs. It’s kinda weird to be honest….

Why it’s worse than you think

Anyway, the way it works is this: The Flash player intercepts exceptions like this and handles it for you. “That’s okay,” you’re thinking. “As long as my user knows something went wrong, I won’t have automatic exception handling, but at least they’ll know to email me when they see the error dialog.” What I haven’t mentioned yet is that there IS NO ERROR DIALOG on the runtime installations of the Flash player or in the default installation of Adobe AIR. Yep: When your shiny component throws an exception deep in the bowels, your users will know something went wrong because the app might start acting “strange” a few minutes later for who knows what reason. Some people in the Flex world get around this by telling their users to install the debug player of Flash. Even though that would be a crazy solution, I don’t have that luxury since we’re deploying in Adobe AIR.

Why it’s even worse than that

Thanks to Doug McCune’s excellent post on this topic, I saw that someone was Monkey Patching their Flex libraries to add some code to try and catch most errors. That got me thinking: “I’ll just monkey patch a low-level class like SystemManager to intercept most of the event dispatches and make sure I have a try-catch around it!” That’s all well and good, except that if an exception happens as the result of a “EventDispatcher.dispatchEvent”, your code will never know that an exception happened. That’s because the flash player is in charge of that handy dispatchEvent method, and it will happily swallow up your exception, display nothing to the user, and return the code to you as if nothing happened. (In case you’re wondering, the return value of dispatchEvent is still “true” even though it failed due to an exception). I learned all about this from Luke Bayes‘ excellent blog post on the topic.

Yep, still worse

At one point I thought that I’d just turn logging on and watch where my application’s error output was being sent. If I see an error, “BAM!” crash report time! From everything I’d read, the only way to get logging was with a debug flash player. AIR doesn’t have a debug version (or so I thought), so that looked like a dead end.

Some light at the end of the tunnel

I found out about Luke’s post from Jörg Birkhold’s post about his cool discovery that you can easily catch exceptions that are a result of “callLater” functions. That’s awesome, and it’s going to make this job 50% easier. You don’t even have to monkey-patch. So, that takes care of “callLater”, which will take care of a lot of the drawing code and plenty of other behind-the-scenes stuff that I don’t quite understand. That still doesn’t cover exceptions as the result of a dispatched event though, which means an uncaught exception as the result of user input is going to be ignored…

I’m getting desperate here…

Since the current dispatchEvent function swallows our exceptions, and a lot of our unexpected exceptions will be in response to events like mouse or keyboard input, maybe there is a way I can make the SystemManager use my own dispatchEvent method so I don’t have to rely upon the one built into Flash Player. Nope. You can’t implement your own IEventDispatcher without using EventDispatcher.dispatchEvent. It’s a good thing – that solution was going to be messy…

Popping up error messages in the release version of AIR!

When re-reading Doug’s post I saw my comment at the bottom that said, ‘For our beta testers (who are obviously more hardcore), I plan on using this cookbook trick to get it to pop up the error dialog: http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&postid=13206&loc=en_US&productid=4

I had forgotten all about that! Turns out that if you drop an empty file called “Debug” into your application’s META-INF/AIR folder, AIR will happily pop up an ActionScript error box, complete with stack trace, in case of an exception. Zavi discovered this by using Procmon, which is an excellent tool.

An app can set its own debug flag

So first I decided to see if the application itself could write that debug file out itself on startup. The answer is:
Macs: Yes
Windows XP: Yes
Vista and up: No!

Vista and Windows 7 have strict permissions around writing to Program Files, so that’s not going to work, but let’s just punt on that for now. So sure enough, I’ve got it writing the magic debug file at startup in the Application’s creationComplete event handler. Unfortunately, it appears that by the time the app can write this file out, AIR seems to have decided whether or not it’s in debug mode (not 100% confirmed yet), so if this goes into production, the app would have to restart itself when it first launches, but that would be doable. Even if I wrote the code in the first line of SystemManager, the AIR runtime is bootstrapped by then, so I doubt there is a way around this. On Windows, I think an external process is going to be required to install this file, but if you’re talking about hardcore beta testers, that might be okay.

Wait – that probably means we can turn on logging!

Something Zavi said in his post about that putting the AIR player into debug mode got me thinking: What if it really is just the Flash player running in debug? That means I might be able to turn on logging! I fired up ProcMon myself and sure enough, there were some beautiful calls to try and read mm.cfg, the Flash Player debug configuration file. I my mm.cfg in the right location for XP and told it to log traces and errors.

[code lang="as3"]ErrorReportingEnable=1
TraceOutputFileEnable=1[/code]

I fired my test app up again (one that throws an exception right when it launches), and I saw not only did I get a popup telling me about the error, but I simultaneously got the entire stack trace written out to the flashlog.txt log file! I also verified that the AIR app can read from the flash log file as it’s running. Now that I can watch the flashlog.txt file for changes, I have a way to detect with certainty if there is ever an exception anywhere in an AIR app. I need to turn this into a library and clean code, and it’s possible that I’m overlooking something, but with this, coupled with Jörg’s callLater handling, and I think we have all of the bases covered.

So, what risks am I running by running the app in debug mode? How big of a performance hit are we talking here?

I’ll post more as I finish up the code to verify that this works, but when YNAB 3 goes into beta, I think we’re going to have a way for people to automatically submit bugs, and I can’t tell you how releaved I am about that!

8 Responses to “Global Exception Handling / Crash Reporting in Adobe AIR – Partially Solved?”

  1. Matt Towers October 1, 2009 at 9:46 am #

    Hello,
    Thanks for the article! Great work. I’m stunned that Adobe doesn’t officially accommodate this. The canonical bug for this problem has over 400 votes in the Adobe JIRA database.

    In any case, were you successful in getting your library to work? Or moreover, would you consider sharing it? Should you decide to, I’d be happy to offer my services to help maintain it.

    Thanks again!

    -Matt Towers

  2. admin October 2, 2009 at 1:08 pm #

    @Matt, you’re quite welcome. :)
    I haven’t gotten the library fully developed yet. What you see above is about as far as I’ve gotten. We’ll be going to beta with YNAB 3 very soon though, and I’ve got to get it working before then, so expect more updates soon. I am nervous about my ability to do this on Vista/Windows 7. We’ll see…

    And yeah, I think sharing it would be a great idea! Lord knows I wanted someone to have already written this. :) I’ll put some thought into how I want to do it and let you know.

  3. Matt Towers October 2, 2009 at 1:28 pm #

    Maybe put it on googlecode? I’ve used a bunch of as3 libs from there. The SVN access alone for keeping up to date is worth the price of admission.

  4. CaioToOn! October 9, 2009 at 10:53 am #

    Seems like this problem will be addressed on Flash Player 10.1

    Look: http://labs.adobe.com/technologies/flashplayer10/features.html#developer

    CaioToOn!

    • admin October 11, 2009 at 5:43 pm #

      What great news! Thanks for the comment! I was excited to see this too. Now my only complaint is that I wish 10.1 was already out, as we’re shipping before 2010. Maybe I’ll try to grin and bear it before then. If we get a lot of unexplained errors, I’ll buckle down and implement this…Decisions, decisions!

  5. Matt Towers January 25, 2010 at 8:58 pm #

    Hiya,
    Any updates on this? I’m releasing an alpha of our product next week and getting good log data…well, you know…

    -matt

Trackbacks/Pingbacks

  1. AIR Exception Handling/Crash Reporting (cont) - September 18, 2009

    [...] just verified that my technique as previously described works regardless of whether my AIR’s .swf file is debug or release. In release builds, I [...]

  2. Stack traces in AIR Release Builds | Martin McBrearty - April 28, 2011

    [...] gets stripped when compiling your release build. Here’s a great little trick discovered by TayTay to allow you to see full stack traces in the debug error alert, just as you would with your debug [...]

Leave a Reply