Exception Tracking With Unity3D
I’ve started out by writing a long and philosophical article on exception handling and tracking in games only to realize it was far too long and entirely missed the point – why and how to implement exception tracking in Unity.
Exception Handling or Exception Tracking?
Exception handling is great both in concept and in practice, however, it makes little sense in most cases when it comes to games. Games are usually very dependent on all modules and subsystems to function properly, and most exceptions result in unrecoverable states.
Renderer failed to initialize? no game for you!
Corrupt data file? no point in trying to recover from that.
The list obviously goes on, but you get the general notion – exception handling is not very useful when it comes to games, the norm says you should make assertions, not exceptions.
That said, while handling exceptions is not something you’ll likely do in a game, it does not mean you don’t want to know when and where an exception occurred.
Why Should I Track Exceptions?
There are many reasons you might want to track exceptions.
When doing QA, especially when doing manual tests, the ability to provide an accurate exception description along with a stack trace will greatly reduce the time required to fix problems. The usefulness becomes more apparent when dealing with difficult to reproduce scenarios.
But tracking exceptions is not something you want to stop doing when leaving the QA stage, as it provides great value on production code as well. Tracking exception reports allows you to monitor your production codebase health, locate exceptional behavior which was not discovered while QAing, something which can commonly occur with mobile games due to the insanely large fragmentation in available platforms, and provide insights needed to prioritize fixes.
Implementation
Implementation breaks down into two parts:
This first part is tracking exception at system level. To do this you can leverage the fact C# is very exception oriented and almost every error will generate an exception, that exception will bubble up and if uncaught on the game code level will get caught by the engine and generate an exception report log.
Unity provide an event you can use to track any log reports, so you will assume any exception logged by the engine was unhandled (unless it was rethrown, but even then you probably want to know about it).
You can use this script I’ve put together to track relevant events and process them. Fill in the log methods with your tracking code and you’re good to go!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
using UnityEngine; using System.Collections; public class LogRouter : MonoBehaviour { private static LogRouter Instance { get; set; } void Awake() { if ( Instance != null ) { DestroyImmediate( gameObject ); return; } Instance = this; DontDestroyOnLoad( gameObject ); } void OnEnable() { Application.RegisterLogCallback( OnLog ); } void OnDisable() { Application.RegisterLogCallback( null ); } void OnLog( string condition, string stackTrace, LogType type ) { switch( type ) { case LogType.Assert: LogAssertion( condition, stackTrace ); break; case LogType.Error: LogError( condition, stackTrace ); break; case LogType.Exception: LogException( condition, stackTrace ); break; case LogType.Warning: LogWarning( condition, stackTrace ); break; case LogType.Log: LogMessage( condition, stackTrace ); break; } } void LogAssertion( string condition, string stackTrace ) { // Log tracking goes here... } void LogException( string condition, string stackTrace ) { // Log tracking goes here... } void LogError( string condition, string stackTrace ) { // Log tracking goes here... } void LogWarning( string condition, string stackTrace ) { // Log tracking goes here... } void LogMessage( string condition, string stackTrace ) { // Log tracking goes here... } } |
The second part of the implementation is logging your exception events using an analytics or event tracking solution.
Most mobile games already feature tracking and analytics solutions to monitor player behavior and game performance, so assuming you have one or more of these in your game, it’s only a matter of packing and dispatching the events. As for how to package the events, it really depends on the solution you have – but a good starting point would be to log events per session when QAing, and aggregate them by stack trace when in production to track common exceptions and causes.
If you don’t have an analytics solution, you can use Google Analytics which is free and has specific methods for tracking exceptions and a Unity plugin readily available (https://github.com/googleanalytics/google-analytics-plugin-for-unity).
Conclusions
To sum things up, tracking exceptions is a very simple and straightforward process in Unity, and I really can’t think of a good reason not to do it. You can get a solution up and running in less than an hour, which will more than pay for itself with the first bug you fix in no time through the insights gained.