Need to handle uncaught exception and send log file

android uncaughtexceptionhandler example
uncaught exceptions
android global exception handler
how to handle app crash in android
unhandled exception android
app has crashed, executing customactivityoncrash's uncaughtexceptionhandler
kotlin uncaughtexceptionhandler example
handle runtime exception in android

UPDATE: Please see "accepted" solution below

When my app creates an unhandled exception, rather than simply terminating, I'd like to first give the user an opportunity to send a log file. I realize that doing more work after getting a random exception is risky but, hey, the worst is the app finishes crashing and the log file doesn't get sent. This is turning out to be trickier than I expected :)

What works: (1) trapping the uncaught exception, (2) extracting log info and writing to a file.

What doesn't work yet: (3) starting an activity to send email. Ultimately, I'll have yet another activity to ask the user's permission. If I get the email activity working, I don't expect much trouble for the other.

The crux of the problem is that the unhandled exception is caught in my Application class. Since that isn't an Activity, it's not obvious how to start an activity with Intent.ACTION_SEND. That is, normally to start an activity one calls startActivity and resumes with onActivityResult. These methods are supported by Activity but not by Application.

Any suggestions on how to do this?

Here are some code snips as a starting guide:

public class MyApplication extends Application
{
  defaultUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler();
  public void onCreate ()
  {
    Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
    {
      @Override
      public void uncaughtException (Thread thread, Throwable e)
      {
        handleUncaughtException (thread, e);
      }
    });
  }

  private void handleUncaughtException (Thread thread, Throwable e)
  {
    String fullFileName = extractLogToFile(); // code not shown

    // The following shows what I'd like, though it won't work like this.
    Intent intent = new Intent (Intent.ACTION_SEND);
    intent.setType ("plain/text");
    intent.putExtra (Intent.EXTRA_EMAIL, new String[] {"me@mydomain.com"});
    intent.putExtra (Intent.EXTRA_SUBJECT, "log file");
    intent.putExtra (Intent.EXTRA_STREAM, Uri.parse ("file://" + fullFileName));
    startActivityForResult (intent, ACTIVITY_REQUEST_SEND_LOG);
  }

  public void onActivityResult (int requestCode, int resultCode, Intent data)
  {
    if (requestCode == ACTIVITY_REQUEST_SEND_LOG)
      System.exit(1);
  }
}

Here's the complete solution (almost: I omitted the UI layout and button handling) - derived from a lot of experimentation and various posts from others related to issues that came up along the way.

There are a number of things you need to do:

  1. Handle uncaughtException in your Application subclass.
  2. After catching an exception, start a new activity to ask the user to send a log.
  3. Extract the log info from logcat's files and write to your own file.
  4. Start an email app, providing your file as an attachment.
  5. Manifest: filter your activity to be recognized by your exception handler.
  6. Optionally, setup Proguard to strip out Log.d() and Log.v().

Now, here are the details:

(1 & 2) Handle uncaughtException, start send log activity:

public class MyApplication extends Application
{
  public void onCreate ()
  {
    // Setup handler for uncaught exceptions.
    Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
    {
      @Override
      public void uncaughtException (Thread thread, Throwable e)
      {
        handleUncaughtException (thread, e);
      }
    });
  }

  public void handleUncaughtException (Thread thread, Throwable e)
  {
    e.printStackTrace(); // not all Android versions will print the stack trace automatically

    Intent intent = new Intent ();
    intent.setAction ("com.mydomain.SEND_LOG"); // see step 5.
    intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // required when starting from Application
    startActivity (intent);

    System.exit(1); // kill off the crashed app
  }
}

(3) Extract log (I put this an my SendLog Activity):

private String extractLogToFile()
{
  PackageManager manager = this.getPackageManager();
  PackageInfo info = null;
  try {
    info = manager.getPackageInfo (this.getPackageName(), 0);
  } catch (NameNotFoundException e2) {
  }
  String model = Build.MODEL;
  if (!model.startsWith(Build.MANUFACTURER))
    model = Build.MANUFACTURER + " " + model;

  // Make file name - file must be saved to external storage or it wont be readable by
  // the email app.
  String path = Environment.getExternalStorageDirectory() + "/" + "MyApp/";
  String fullName = path + <some name>;

  // Extract to file.
  File file = new File (fullName);
  InputStreamReader reader = null;
  FileWriter writer = null;
  try
  {
    // For Android 4.0 and earlier, you will get all app's log output, so filter it to
    // mostly limit it to your app's output.  In later versions, the filtering isn't needed.
    String cmd = (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) ?
                  "logcat -d -v time MyApp:v dalvikvm:v System.err:v *:s" :
                  "logcat -d -v time";

    // get input stream
    Process process = Runtime.getRuntime().exec(cmd);
    reader = new InputStreamReader (process.getInputStream());

    // write output stream
    writer = new FileWriter (file);
    writer.write ("Android version: " +  Build.VERSION.SDK_INT + "\n");
    writer.write ("Device: " + model + "\n");
    writer.write ("App version: " + (info == null ? "(null)" : info.versionCode) + "\n");

    char[] buffer = new char[10000];
    do 
    {
      int n = reader.read (buffer, 0, buffer.length);
      if (n == -1)
        break;
      writer.write (buffer, 0, n);
    } while (true);

    reader.close();
    writer.close();
  }
  catch (IOException e)
  {
    if (writer != null)
      try {
        writer.close();
      } catch (IOException e1) {
      }
    if (reader != null)
      try {
        reader.close();
      } catch (IOException e1) {
      }

    // You might want to write a failure message to the log here.
    return null;
  }

  return fullName;
}

(4) Start an email app (also in my SendLog Activity):

private void sendLogFile ()
{
  String fullName = extractLogToFile();
  if (fullName == null)
    return;

  Intent intent = new Intent (Intent.ACTION_SEND);
  intent.setType ("plain/text");
  intent.putExtra (Intent.EXTRA_EMAIL, new String[] {"log@mydomain.com"});
  intent.putExtra (Intent.EXTRA_SUBJECT, "MyApp log file");
  intent.putExtra (Intent.EXTRA_STREAM, Uri.parse ("file://" + fullName));
  intent.putExtra (Intent.EXTRA_TEXT, "Log file attached."); // do this so some email clients don't complain about empty body.
  startActivity (intent);
}

(3 & 4) Here's what SendLog looks like (you'll have to add the UI, though):

public class SendLog extends Activity implements OnClickListener
{
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    requestWindowFeature (Window.FEATURE_NO_TITLE); // make a dialog without a titlebar
    setFinishOnTouchOutside (false); // prevent users from dismissing the dialog by tapping outside
    setContentView (R.layout.send_log);
  }

  @Override
  public void onClick (View v) 
  {
    // respond to button clicks in your UI
  }

  private void sendLogFile ()
  {
    // method as shown above
  }

  private String extractLogToFile()
  {
    // method as shown above
  }
}

(5) Manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >
    <!-- needed for Android 4.0.x and eariler -->
    <uses-permission android:name="android.permission.READ_LOGS" /> 

    <application ... >
        <activity
            android:name="com.mydomain.SendLog"
            android:theme="@android:style/Theme.Dialog"
            android:textAppearance="@android:style/TextAppearance.Large"
            android:windowSoftInputMode="stateHidden">
            <intent-filter>
              <action android:name="com.mydomain.SEND_LOG" />
              <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
     </application>
</manifest>

(6) Setup Proguard:

In project.properties, change the config line. You must specify "optimize" or Proguard will not remove Log.v() and Log.d() calls.

proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt

In proguard-project.txt, add the following. This tell Proguard to assume Log.v and Log.d have no side effects (even though they do since they write to the logs) and thus can be removed during optimization:

-assumenosideeffects class android.util.Log {
    public static int v(...);
    public static int d(...);
}

That's it! If you have any suggestions for improvements to this, please let me know and I may update this.

Handling Uncaught-Exceptions in Android, Get convenient ways to handle uncaught exceptions for developers and Sometimes you even have to save those logs to a file if you are� The uncaught-exception module supports doing a graceful shutdown. Normally when an uncaught exception happens you want to close any servers that are open and wait for all sockets to exit cleanly. This function only gets called if abortOnUncaught is set to true. Ideally you want to empty the event loop and do a full graceful shutdown.

Today there are many crash reprting tools that do this easily.

  1. crashlytics - A crash reporting tool, free of charge but gives you basic reports Advantages : Free

  2. Gryphonet - A more advanced reporting tool, requires some kind of fee. Advantages : Easy recreation of crashes, ANR's, slowness...

If you are a private developer I would suggest Crashlytics, but if it's a big organization, I would go for Gryphonet.

Good Luck!

Android Handling the Unexpected, In Android, the answer is to create an UncaughtExceptionHandler. object that you want to handle any uncaught Throwable of a thread. logging the issue since the logs are on the device and not sent to you. In most cases, you simply add the package's JAR file(s) to your app and use their API to log. public class UnhandledExceptionLogger : ExceptionLogger { public override void Log(ExceptionLoggerContext context) { var log = context.Exception.ToString(); //Write the exception to your logs } } You then need to register your exception logger as part of the startup configuration of Web API.

Try using ACRA instead - it handles sending the stack trace as well as tons of other useful debug information to your backend, or to Google Docs document you've set up.

https://github.com/ACRA/acra

Logging Exceptions in Java, A look at common approaches to exception handling and logging in For example, imagine we have a program that writes a string to a file. In this class, we catch and log any IOExceptions: setDefaultUncaughtExceptionHandler(), which lets you specify an exception handler for uncaught exceptions for� I am trying to find a way to catch all errors in my project and save them to the database as well as file log. I have create the following middleware which helps me in that need but the only problem I am facing using winston is that once uncaughtException or unhandledRejection is handled the app is terminated.

@PeriHartman's answer works well when the UI thread throws uncaught exception. I made some improvements for when the uncaught exception is thrown by a non UI thread.

public boolean isUIThread(){
    return Looper.getMainLooper().getThread() == Thread.currentThread();
}

public void handleUncaughtException(Thread thread, Throwable e) {
    e.printStackTrace(); // not all Android versions will print the stack trace automatically

    if(isUIThread()) {
        invokeLogActivity();
    }else{  //handle non UI thread throw uncaught exception

        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                invokeLogActivity();
            }
        });
    }
}

private void invokeLogActivity(){
    Intent intent = new Intent ();
    intent.setAction ("com.mydomain.SEND_LOG"); // see step 5.
    intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // required when starting from Application
    startActivity (intent);

    System.exit(1); // kill off the crashed app
}

Error handling on Android part 2: implementing an , How many times have you been in the middle of using a new shiny How do I implement a custom UncaughtExceptionHandler for a JVM allows us to handle uncaught exceptions in JVM applications. generates a diagnostic report that could be sent to an error reporting API. Error Logging Software. For example, When you try to open a file on disk, it is a common problem for the file to not exist. The .NET Framework will then throw a FileNotFoundException. This is a simple example of a potential known problem that is accounted for within the code. An unhandled exception occurs when a developer does not anticipate and handle a potential

Nicely explained. But one observation here, instead of writing into file using File Writer and Streaming, I made use of the logcat -f option directly. Here is the code

String[] cmd = new String[] {"logcat","-f",filePath,"-v","time","<MyTagName>:D","*:S"};
        try {
            Runtime.getRuntime().exec(cmd);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

This helped me in flushing the latest buffer info. Using File streaming gave me one issue that it was not flushing the latest logs from buffer. But anyway, this was really helpful guide. Thank you.

Logging uncaught exceptions in Python applications — Scry , You want to be able to get good logging data from your applications to be able needs, however uncaught exceptions is something it can't handle on its own. the ability to send in a log with enough details to start pointing you in the a technical user and uploading a log file is much easier to explain then� The best way to log exceptions is to provide a specific log message for each possible exception. Always ensure that sufficient information is being logged and that nothing important is being excluded. This will be discussed in more detail later.

Logging uncaught exception (redirecting from sysout to logger , Even though most of the time System.err is redirected to a file system, I wanted a UncaughtExceptionHandler to handle any such exceptions. Handling exceptions in a Web service is no different than handling exceptions in a Web or Windows application. However, when designing exception blocks in Web services, you need to be aware of the fact that you need to communicate the exception information to the consumers of your Web service in a platform-independent manner based on the SOAP specification.

How to Handle Exceptions in Java, The standard practice is to record all events in the application log file. Uncaught or runtime exceptions happen unexpectedly, so you may not have a try -catch� Yep, I +1'd you for using the right technique if you're going to go the uncaughtException route, I just wanted to amplify that it's not the best route, and discourage the OP from thinking he should do what you have and then embed some kind of email sender in the event listener.

Errors & Logging - Lumen, If you would like to have complete control over how Monolog is configured for your The report method is used to log exceptions or send them to an external By default, exceptions resulting from 404 errors are not written to your log files. Rather than log directly at the source, we can pass the exception up the stack and log it at a point where we have more contextual information. This can take place in the middle of the call stack, or even by an umbrella handler at the top.

Comments
  • Personally I just use ACRA, although it is open source so you could check how they do it...
  • Just a note: never call System.exit. You'll be breaking the uncaught exception handlers chain. Just forward it to the next. You already have "defaultUncaughtHandler" from getDefaultUncaughtExceptionHandler, just pass the call to it when you're done.
  • @gilm, can you provide an example on how to "forward it to the next" and what else might happen in the handler chain? It's been a while, but I tested a number of scenarios, and calling System.exit() seemed to be the best solution. After all, the app has crashed and it needs to terminate.
  • I think I recall what happens if you let the uncaught exception continue: the system puts up the "app terminated" notice. Normally, that would be fine. But since the new activity (that sends email with the log) is already putting up its own message, having the system put up another is confusing. So I force it to abort quietly with System.exit().
  • @PeriHartman sure: there is only one default handler. before calling setDefaultUncaughtExceptionHandler(), you must call getDefaultUncaughtExceptionHandler() and keep that reference. So, say you have bugsense, crashlytics and your handler is the last installed, the system will call yours only. it's your task to call the reference that you received via getDefaultUncaughtExceptionHandler() and pass the thread and throwable to the next in chain. if you just System.exit(), the others won't be called.
  • You also need to register your implementation of Application in the manifest with an attribute in the Application tag, e.g.: <application android:name="com.mydomain.MyApplication" other attrs... />
  • I believe I tried that (or something similar). If I recall, I ran into permission problems. Are you doing this on a rooted device?
  • Oh, I am sorry if I confused you, but I am so far trying with my emulators. I am yet to port it to a device (but yes the device I use for testing is a rooted one).