×

Facebook Sonar Is a Visual and Interactive Debugging Tool for Mobile Apps

MMS Founder
MMS RSS

Facebook Sonar is an open-source toolset that aims to help developers inspect and understand the structure and behaviour of iOS and Android apps in a visually rich, interactive, and extensible way.

According to Facebook engineer Emil Sjölander, Sonar was built upon the experience gathered with Stetho, an Android debugging bridge allowing developers to debug their apps using Chrome DevTools, with the aim to design a more extensible tool that could also target the iOS platform. Not all Stetho features have equivalents in Sonar, however. Therefore, developers should continue using Stetho when they need features such as command-line tools to dump an app’s state.

For extensibility, Sonar provides a plugin API that allows developers to create their own plugins to visualize and debug data coming from apps. Sonar initial release includes a number of ready-to-use plugins, such as Logs, to inspect system logs coming from an app; Layout Inspector, to inspect the layout of both iOS and Android apps; and, Network Inspector, to inspect network traffic. Those are just basic examples of what Sonar makes possible. According to Sjölander, Facebook engineers also developed plugins to monitor streams of GraphQL requests, track performance markers, and more.

To use Sonar, a mobile app should integrate with Sonar SDK, which is in charge of communicating back and forth with a Electron-based desktop app showing the debugging data. A Sonar plugin has both a desktop and a mobile component. A desktop plugin is written using React and is in charge of communicating with the remote plugin and rendering its data. A mobile plugin is written either in Swift/Objective-C or in Java/Kotlin and registers a number of handlers and responses to manage requests coming from its desktop counterpart.

Once you have setup your project to use Sonar, either using Gradle or CocoaPods, initializing it inside of your app is pretty straightforward, as shown in the examples below:

// Android
public class MyApplication extends Application {

  @Override
  public void onCreate() {
    super.onCreate();

    if (BuildConfig.DEBUG && SonarUtils.shouldEnableSonar(this)) {
      final SonarClient client = AndroidSonarClient.getInstance(this);
      client.addPlugin(new MySonarPlugin());
      client.start();
    }
  }
}
// iOS
#import <SonarKit/SonarClient.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#if DEBUG
  SonarClient *client = [SonarClient sharedClient];
  [client addPlugin:[MySonarPlugin new]];
  [client start];
#endif
  ...
}
@end

A known limitation of Sonar on the iOS platform is its inability to run within Swift apps, due to a number of C++

Subscribe for MMS Newsletter

By signing up, you will receive updates about our latest information.

  • This field is for validation purposes and should be left unchanged.

How to use the Python debugger

MMS Founder
MMS RSS

This article is not about machine learning, but about a piece of software engineering that often comes handy in data science practice. When writing code, everybody gets errors. Sometimes it is difficult to debug them. Using a debugger may help, but can also be intimidating. This is a TLDR tutorial in using pdb in IPython, focused on looking at variables inside functions.

The advantage of having global variables is that when a script stops with an error, you can look at the variables to discover the cause. With functions, no such luck. And of course any non-trivial software needs functions.

This is where the debugger comes in. Python comes with a debugger called pdb. We will look at using it within IPython.


May your code be as strong and as free of errors as this blockchain

First, you turn it on:

In [1]: pdb
Automatic pdb calling has been turned ON

Better yet, you have an option of choosing to go into debug mode only after an error. In such case, you just type debug post factum. Thanks to Ehud Ben-Reuven for pointing this out.

Both pdb and debug are IPython magic commands, so their official syntax is %pdb and %debug. The shorter forms work if there aren’t any globals of these names.

Now, let’s define a function:

def add_two( x ):
    return x + 2

When an error occurs, you’ll get a debugger prompt:

In [3]: add_two('two')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-a77015a373f8> in <module>()
----> 1 add_two('two')

<ipython-input-8-a95bdacf8a55> in add_two(x)
      1 def add_two( x ):
----> 2         return x + 2

TypeError: cannot concatenate 'str' and 'int' objects
> <ipython-input-8-a95bdacf8a55>(2)add_two()
      1 def add_two( x ):
----> 2         return x + 2

ipdb>

Or, with automatic pdb calling off (spot one difference):

In [3]: add_two('two')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-a77015a373f8> in <module>()
----> 1 add_two('two')

<ipython-input-1-3da9f0985321> in add_two(x)
      1 def add_two( x ):
----> 2     return x + 2

TypeError: cannot concatenate 'str' and 'int' objects

In [4]: debug
> <ipython-input-1-3da9f0985321>(2)add_two()
      1 def add_two( x ):
----> 2     return x + 2

ipdb>

In this example the error is obvious and spelled out in the message, so we don’t really need a debugger. The point is to get familiar with it for real-world usage.

The pdb accepts a number of commands, many of which are one letter. You can list them with h.

For our purposes, the most important command is p, for “print”:

ipdb> h p
p expression
Print the value of the expression.
ipdb> p x
'two'   

Frames

When using an external library, stack trace consists of many frames. In English it means that a function called a function which called a function and so on, and somewhere in this stack the error occured. Most often one is interested in finding an error in own code, but the debugger lands at the innermost, deepest function. We need to move up the stack, and the command to do it is u. You type it until the familiar snippet of code shows. Now you can inspect the variables.

Traces/breakpoints

You don’t need an error to get into the debugger. It is enough to set a trace, or a breakpoint, somewhere in the code:

import pdb; pdb.set_trace()

When execution reaches this point, the program will stop and you’ll get a debugger prompt. To continue exectution, use the c command.

You can also add a breakpoint from within the debugger with the b command.

Quitting

q quits the debugger. You can also exit with Ctrl-D.

When you’re done debugging and don’t want debugger prompt on errors, you turn it off:

In [5]: pdb
Automatic pdb calling has been turned OFF

That’s the gist of. Not really a rocket science, is it?

Subscribe for MMS Newsletter

By signing up, you will receive updates about our latest information.

  • This field is for validation purposes and should be left unchanged.