Catch javascipt Ionic Exceptions and errors in native code for Analytics


#1

Hello,

I want to share what I did to handle Javascript Exceptions in native code.

Today I use good crash analytic tool www.crashlytics.com that helps me to analyse exceptions and crashes. But what happens if something happens wrong in Ionic? I use Ionic word because Ionic framework filters all exceptions and therefore for most errors the Exception seems like:

 ReferenceError: bfbfbbf is not defined
     at new <anonymous> (file:///android_asset/www/js/groups/groupsController.js:62:2)
     at d (file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:65:479)
     at Object.instantiate (file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:66:103)
     at file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:97:467
     at d (file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:340:27957)
     at file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:340:28433
     at N (file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:85:92)
     at g (file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:78:61)
     at N (file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:85:33)
     at g (file:///android_asset/www/lib/js/ionic/1.0.0-beta.11-ionic.bundle.min.js:78:82)  

So how to catch it and send Exception report?

app.config(function($provide) {
            $provide.decorator("$exceptionHandler", function($delegate, $injector) {
                return function(exception, cause) {
    
                    if (false) { //(appState !== "...") { // We want to only send the error in this case

                        $delegate(exception, cause);

                    } else {
                        //appState == null;

                        var MyCordovaService = $injector.get("MyCordovaService");

                        console.debug({reason: exception, message: exception.message, stack: exception.stack});

                        var data = {
                            message: "Exception: " + exception.message, 
                            stack: exception.stack
                        };

                       // here we send report to native side
                        MyCordovaService.reportClientError(data).then(function(data) {
                            console.debug('reportClientError success', data);
                        }, function(error) {
                            console.debug('reportClientError fail!', error);
                        });

                        // Call The original Angular Exception Handler
                        $delegate(exception, cause);
                    }
                };
            });    
        });

Android side:

private boolean reportClientToCrashlytics(final JSONArray args,	final CallbackContext callbackContext) {
		this.cordova.getThreadPool().execute( new Runnable() {
			public void run() {
				try {
					JSONObject root = args.optJSONObject(0);

					Log.d(TAG, "sendAcceptEvent: " + root.toString());

					JSONObject eventStructure = root.getJSONObject("eventStructure");

					String message = eventStructure.getString("message");	
					String stack = eventStructure.getString("stack");	
					
					
					try {							
						throw new WmIonicException(message + "\n==============================" + stack);
					} catch (Exception e) {
						e.printStackTrace();
						WmAnalyticsReport.reportException(e);
					}					
					
				} catch (JSONException e) {
					e.printStackTrace();
					callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ContactManager.NOT_SUPPORTED_ERROR));
				}
			}
		});		

		return true;
	}

public class WmAnalyticsReport {
	
	private WmAnalyticsReport() {}
	
	public static void reportException(Throwable e){
		Crashlytics.logException(e);
	}	
}

#2

Hi Shoustin,
Could you please elaborate how to write android part in ionic project?

Thanks
Rajul


#3

Wrap data from javascript (Exception) with throw new Exception(....), catch it and send with Crashlytics:

// report crashes to crashlytics
private boolean reportClientToCrashlytics(final JSONArray args,
		final CallbackContext callbackContext) {

	this.cordova.getThreadPool().execute(new Runnable() {
		public void run() {
			try {
				JSONObject eventStructure = getJsonArgs(args,
						"reportClientError", callbackContext);

				Timber.d("reportClientToCrashlytics -> "
						+ eventStructure.toString());

				String message = eventStructure.getString("message");
				String stack = eventStructure.getString("stack");

				try {
					throw new WmIonicException(message
							+ "\n==============================" + stack);
				} catch (Exception e) {
					// reportPluginError(e, callbackContext);
					callbackContext.success();
					WmAnalyticsReport.reportException(e);
				}

			} catch (JSONException e) {
				reportPluginError(e, callbackContext);
			}
		}
	});

	return true;
}

public class WmAnalyticsReport {
	
	private WmAnalyticsReport() {}
	
	public static void reportException(Throwable e){
		Log.d("WmAnalyticsReport", "reportClientToCrashlytics: " + e.toString());
		Crashlytics.logException(e);
	}
	
	
	public static void reportLog(String str){
		Crashlytics.log(Log.ERROR, "Wanameet", str); 
	}
	
}

public class WmIonicException extends Exception{
	

	private static final long serialVersionUID = 1L;

	public WmIonicException(String string) {
		super(string);
	}
}