How to create Production Application Error Report (Client)

Asked

Viewed 1,016 times

5

I am looking for a way (efficient and practical) to capture globally all Exceptions not dealt with by the application (the ones that lead the application to crash or "Application stopped working!").

Questions:

  • Is there any method void main(), as in Java I can capture these exceptions on a centralised basis before application crash?
  • There is some feature available in the Android API, for these purposes?
  • What would be the most efficient and practical way to create this resource?

I would like an implementation solution, I would not like to use third-party libraries. Because I believe that my final implementation would be something very unique and specific. = D

Additional information: What should be possible to do in the global Exceptions catcher (Accessible resources) (It is not necessary to implement these cases in the response (it is only information needed for continuity of implementation)):

  • Capture the Exception Stack;
  • Can instantiate and use the package java.io; (for recording logs in archive)
  • (Optional) Have access to Context of the application, in order to instantiate a connection to Sqlite; (for recording the logs in a database)

Obs: I do not want to try to recover the application, but only to have this information so that I can analyse it and improve the efficiency of the application.

Detail: I have seen this question here at Sopt and did not assist me in my doubt.

2 answers

6


Exactly like the Paulo Rodrigues cited, Android, more specifically JVM, allows to register a Handler for Exception's untreated.

And, I believe, any library that allows report use the same technique.

Treating Exception’s not caught

The simplest and perhaps organized way to do it is by using the class Application. Where at the beginning of the application, in the method onCreate, you register the Handler.

An example I use a lot:

public class Application extends android.app.Application implements Thread.UncaughtExceptionHandler {

    private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;

    @Override
    public void onCreate() {
        super.onCreate();
        mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        // Aqui você pode tratar a Exception...
        mDefaultExceptionHandler.uncaughtException(thread, ex);
    }
}

Okay, with just that doesn’t answer every question. The Thread.UncaughtExceptionHandler answers only your first question.

With the Thread.UncaughtExceptionHandler I believe it is possible to answer the last two, but it takes a little more code.

Archiving

For the second question, I’m sure it’s possible, because some of the treatments I do in some app’s is write in a file the error log, but I usually use a Thread separate for that.

A simple form:

@Override
public void uncaughtException(Thread thread, final Throwable ex) {
    new Thread(){
        @Override
        public void run() {
            File file = new File("NOME_DO_ARQUIVO");
            FileWriter writer = null;

            try {
                writer = new FileWriter(file);
                writer.write(throwableToString(ex));
            } catch (IOException e) {
            } finally {
                close(writer);
            }
        }
    }.start();
}

private String throwableToString(Throwable t) {
    StringWriter stringWriter = new StringWriter();
    PrintWriter printWriter = new PrintWriter(stringWriter, false);

    t.printStackTrace(printWriter);

    printWriter.flush();
    stringWriter.flush();

    return stringWriter.toString();
}

Saving Exception to Sqlite

Yes, it’s possible. I never got around to it, but according to this project, it is possible.

A leaner example would be:

@Override
public void uncaughtException(Thread thread, final Throwable ex) {
    new Thread(){
        @Override
        public void run() {
            SQLiteDatabase db = new SeuSQLiteOpenHelper(Application.this).getWritableDatabase();

            String sql = "insert into exceptions(exception, created_at) values (?, ?)";

            Object args[] = {
                    throwableToString(ex),
                    System.currentTimeMillis() / 1000
            };

            try { 
                db.execSQL(sql, args);
            } catch(Exception e){
            } finally {
                db.close();
            }
        }
    }.start();
}

And as warned by Fernando, the class statement was missing Application in the Androidmanifest:

<application
    <!-- Demais atributos -->
    android:name=".application.Application" />
  • The case of sqlite is simple, the implementation of the project is that it rolled a little, perhaps because of the MD5. I will put a more streamlined example.

  • This example got bad because it ends up encapsulating the access to bank to centralize the code, but deep down it only makes the call to TCClickUtil to access the SQLiteOpenHelper. I put a more compact example that goes straight to the point.

  • Wakim, just one observation in your reply I found that the class override Application, your method onCreate was not being called by the application at startup, so I deduced that maybe there should be some configuration in the manifest application, then I found this: <application android:name=". Application" ... > where should be informed which the class override in the case of android:name=".Application". If possible add this information to the response body, to make your response even clearer. =)

  • Jeez, that’s right, I’ve already started from that principle, I’ll make it clear to others who come later don’t get lost. Vlw Fernando.

0

High maintenance!

An implementation like this generates other work points and more maintenance, for example!
1 - Create a way to send this log.
2 - Control the replay of the same error. ( N users)
3 - Support connection load and traffic from this log.
4 - Minimize the negative image of a CRASH in your application
5 - Ensure that the sending of log is done even if a CRASH occurs.
6 - Inform and ask the user for authorization to send the error log
and also additional information for.
7 - Implement an application to receive these logs.

Something more professional and worked out thinking about these problems would be!

ACCRA is a library that allows the Android App to automatically post your crash reports in a form of Googledoc(deprecated). It is targeted at Android app developers to help them get data from their applications when they stop working or misbehave.

More information: http://github.com/ACRA/acra/wiki/BasicSetup https://github.com/ACRA/acra/wiki/Backends

  • These points may be relevant for certain applications, for others, this is not always true, as in my case, where it is an enterprise application, where there is already a service responsible for receiving and sending information to the application, where it wouldn’t be a hassle to add that log information. There is also no problem getting duplicate logs, as they can inform various environments where the error is occurring and how often. The log being done manually or with that quoted library will not and should not attempt to retrieve the application from "crash" ...

  • ... continuing. So for the user, it makes no difference. The submission will be made together with the rest of the information already sent by the application to the service, being guaranteed. And this does not require any authorization or intervention from the user, in fact he does not even need to know that it exists (mainly, because it is an enterprise application).

  • @Fernando, I see that your needs are very specific and directed to a closed coporative environment. This solution goes far beyond.

  • Although it is not considered appropriate to my case, it is a good option for simpler cases, where there is no longer a structure available and specific requirements. Just one remark: The cited library no longer supports reporting Logs directly to Google Drive Docs: "The formKey Parameter was used for the now deprecated Googledocs Forms backend. It is still required but not used anymore." (Font: www.acra.ch) and this is also mentioned in the link you posted: "Deprecated - a Google Docs Spreadsheet (default and original behavior) - Please read this notice beforehand"

  • @Fernando, Just like the android API itself, the (deprecated) occur with the evolution of work, this shows that the solution is walking and evolving. The various forms of ACRA use with (third) in https://github.com/ACRA/acra/wiki/Backends! To evaluate the level of applications supported by ACRA is necessary a very extensive and complex evaluation, but since its scope is very large, you can confirm this in the repository evaluations by the collaborators' support chart. https://github.com/ACRA/acra/graphs/contributors

  • Yes, maybe it’s an evolution, but you cited Google Drive as an option: "The Android App automatically post your crash reports in a form of Googledoc", and this option is no longer valid and should not be used.

  • 1

    In the current description, this has not been updated, only in the documentation is informed! I updated here also this (deprecated).

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.