Wie erhalte ich von meiner Android-Anwendung Absturzdaten?



Answers

Für Beispielanwendungen und Debuggingzwecke verwende ich eine einfache Lösung, die es mir ermöglicht, den Stacktrace auf die SD-Karte des Geräts zu schreiben und / oder auf einen Server hochzuladen. Diese Lösung wurde von Project android-remote-stacktrace inspiriert (speziell die Komponenten "save-to-device" und "upload-to-server") und ich denke, es löst das von So- son erwähnte Problem. Es ist nicht optimal, aber es funktioniert und Sie können es verbessern, wenn Sie es in einer Produktionsanwendung verwenden möchten. Wenn Sie sich dazu entschließen, die Stacktraces auf den Server hochzuladen, können Sie sie mit einem PHP-Skript ( index.php ) anzeigen. Wenn Sie interessiert sind, können Sie alle unten stehenden Quellen finden - eine Java-Klasse für Ihre Anwendung und zwei optionale PHP-Skripte für den Server, der die hochgeladenen Stacktraces hostet.

Rufen Sie in einem Kontext (z. B. die Hauptaktivität) auf

if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
    Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(
            "/sdcard/<desired_local_path>", "http://<desired_url>/upload.php"));
}

CustomExceptionHandler

public class CustomExceptionHandler implements UncaughtExceptionHandler {

    private UncaughtExceptionHandler defaultUEH;

    private String localPath;

    private String url;

    /* 
     * if any of the parameters is null, the respective functionality 
     * will not be used 
     */
    public CustomExceptionHandler(String localPath, String url) {
        this.localPath = localPath;
        this.url = url;
        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
    }

    public void uncaughtException(Thread t, Throwable e) {
        String timestamp = TimestampFormatter.getInstance().getTimestamp();
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        e.printStackTrace(printWriter);
        String stacktrace = result.toString();
        printWriter.close();
        String filename = timestamp + ".stacktrace";

        if (localPath != null) {
            writeToFile(stacktrace, filename);
        }
        if (url != null) {
            sendToServer(stacktrace, filename);
        }

        defaultUEH.uncaughtException(t, e);
    }

    private void writeToFile(String stacktrace, String filename) {
        try {
            BufferedWriter bos = new BufferedWriter(new FileWriter(
                    localPath + "/" + filename));
            bos.write(stacktrace);
            bos.flush();
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendToServer(String stacktrace, String filename) {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("filename", filename));
        nvps.add(new BasicNameValuePair("stacktrace", stacktrace));
        try {
            httpPost.setEntity(
                    new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
            httpClient.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

upload.php

<?php
    $filename = isset($_POST['filename']) ? $_POST['filename'] : "";
    $message = isset($_POST['stacktrace']) ? $_POST['stacktrace'] : "";
    if (!ereg('^[-a-zA-Z0-9_. ]+$', $filename) || $message == ""){
        die("This script is used to log debug data. Please send the "
                . "logging message and a filename as POST variables.");
    }
    file_put_contents($filename, $message . "\n", FILE_APPEND);
?>

index.php

<?php
    $myDirectory = opendir(".");
    while($entryName = readdir($myDirectory)) {
        $dirArray[] = $entryName;
    }
    closedir($myDirectory);
    $indexCount = count($dirArray);
    sort($dirArray);
    print("<TABLE border=1 cellpadding=5 cellspacing=0 \n");
    print("<TR><TH>Filename</TH><TH>Filetype</th><th>Filesize</TH></TR>\n");
    for($index=0; $index < $indexCount; $index++) {
        if ((substr("$dirArray[$index]", 0, 1) != ".") 
                && (strrpos("$dirArray[$index]", ".stacktrace") != false)){ 
            print("<TR><TD>");
            print("<a href=\"$dirArray[$index]\">$dirArray[$index]</a>");
            print("</TD><TD>");
            print(filetype($dirArray[$index]));
            print("</TD><TD>");
            print(filesize($dirArray[$index]));
            print("</TD></TR>\n");
        }
    }
    print("</TABLE>\n");
?>
Question

Wie kann ich Absturzdaten (zumindest Stack-Traces) von meiner Android-Anwendung erhalten? Zumindest wenn ich an meinem eigenen Gerät arbeite, das per Kabel zurückgeholt wird, aber idealerweise von jeder Instanz meiner Anwendung, die auf der Festplatte läuft, damit ich sie verbessern und sie solider machen kann.




Sie können dies direkt in Android Studio tun. Schließen Sie einfach Ihr Telefon an, führen Sie die App aus, lassen Sie sie abstürzen, und Sie können den Stacktrace direkt in Android Studio anzeigen.




Ich bin einer der Gründer von Bugsnag die wir genau für diesen Zweck entworfen haben. Bugsnag erfasst automatisch unbehandelte Ausnahmen in Android-Apps und sendet sie an unser Dashboard, wo Sie Fixes priorisieren und in Diagnoseinformationen eintauchen können.

Hier sind einige wichtige Dinge zu beachten, wenn Sie ein Crash-Reporting-System zusammen mit einigen Code-Schnipsel auswählen oder erstellen:

  • Erkennt unbehandelte Ausnahmen automatisch ( Beispielcode )
  • Erfasst Diagnosedaten wie Speichernutzung, Geräteinfo usw. ( Beispielcode )
  • Effektiv stürzen Gruppen durch Grundursache zusammen
  • Ermöglicht die Verfolgung von Aktionen, die der Benutzer vor jedem Absturz ausgeführt hat, um die Reproduktion zu unterstützen ( Beispielcode )

Wenn Sie einige Best Practices rund um das Thema Crash-Handling / -Reporting auf Android sehen möchten, können Sie den vollständigen Quellcode für die Crash-Reporting-Bibliothek von Bugsnag lesen, die vollständig Open Source ist. Zögern Sie nicht, diese auseinander zu nehmen und in Ihren eigenen Anwendungen zu verwenden!




Google Firebase ist die neueste (2016) Methode von Google, mit der Sie Absturz- / Fehlerdaten auf Ihrem Telefon erhalten. Fügen Sie es in Ihre build.gradle-Datei ein:

compile 'com.google.firebase:firebase-crash:9.0.0'

Fatale Abstürze werden automatisch protokolliert, ohne dass Benutzereingaben erforderlich sind, und Sie können auch nicht-tödliche Abstürze oder andere Ereignisse protokollieren:

try
{

}
catch(Exception ex)
{
    FirebaseCrash.report(new Exception(ex.toString()));
}






Gerade begonnen, ACRA https://github.com/ACRA/acra mit Google Formulare als Backend zu verwenden und es ist sehr einfach einzurichten und zu verwenden, es ist die Standardeinstellung.

ABER das Senden von Berichten an Google Formulare wird veraltet (dann entfernt): https://plus.google.com/118444843928759726538/posts/GTTgsrEQdN6 https://github.com/ACRA/acra/wiki/Notice-on-Google-Form-Spreadsheet-usage

Wie auch immer, es ist möglich, einen eigenen Absender zu definieren https://github.com/ACRA/acra/wiki/AdvancedUsage#wiki-Implementing_your_own_sender Sie können versuchen, den Absender zum Beispiel zu mailen.

Mit minimalem Aufwand ist es möglich, Berichte an Bugsense zu senden: http://www.bugsense.com/docs/android#acra

NB Das kostenlose bugsense-Konto ist auf 500 Berichte / Monat begrenzt




Wenn Sie sofort Antworten wünschen, können Sie logcat

$adb shell logcat -f /sdcard/logoutput.txt *:E

Wenn gerade zu viel Junk in deinem Log ist, versuche es zuerst zu löschen.

$adb shell logcat -c

Versuchen Sie dann, Ihre App auszuführen und logcat erneut.




Ich habe eine weitere tolle Webanwendung gefunden, um die Fehlerberichte zu verfolgen.

https://mint.splunk.com/

Kleine Anzahl von Schritten zum Konfigurieren.

  1. Melden Sie sich an oder registrieren Sie sich und konfigurieren Sie über den obigen Link. Sobald Sie mit dem Erstellen einer Anwendung fertig sind, wird eine Zeile wie unten beschrieben bereitgestellt.
Mint.initAndStartSession(YourActivity.this, "api_key");
  1. Fügen Sie im build.gradl der Anwendung Folgendes hinzu.
android {
...
    repositories {
        maven { url "https://mint.splunk.com/gradle/"}
    }
...
}

dependencies {
...
    compile "com.splunk.mint:mint:4.4.0"
...
}
  1. Fügen Sie den oben kopierten Code hinzu und fügen Sie ihn jeder Aktivität hinzu.

    Mint.initAndStartSession (YourActivity.this, "api_key");

Das ist es. Sie melden sich an und gehen zu Ihrem Anwendungs-Dashboard, Sie erhalten alle Fehlerberichte.

Hoffe es hilft jemandem.




In Android 2.2 ist es nun möglich, Crash-Berichte von Android Market-Anwendungen automatisch zu erhalten:

Mit der neuen Fehlerberichterstattung für Android Market-Apps können Entwickler Absturz- und Standberichte von ihren Benutzern erhalten. Die Berichte sind verfügbar, wenn sie sich bei ihrem Publisher-Konto anmelden.

http://developer.android.com/sdk/android-2.2-highlights.html




Sie können auch einen ganzen (einfachen) Service dafür verwenden und nicht nur die Bibliothek. Unsere Firma hat gerade einen Service nur dafür veröffentlicht: http://apphance.com .

Es hat eine einfache .jar-Bibliothek (für Android), die Sie in 5 Minuten hinzufügen und integrieren und dann sammelt die Bibliothek nicht nur Informationen zum Absturz, sondern auch Protokolle von laufenden Anwendungen, und Ihre Tester können Probleme direkt vom Gerät aus melden Gesamter Kontext (Geräte-Rotation, ob es mit einem WLAN verbunden ist oder nicht und mehr). Sie können die Protokolle mit einem sehr schönen und nützlichen Web-Panel ansehen, wo Sie Sitzungen mit Ihrer Anwendung verfolgen können, Abstürze, Logs, Statistiken und mehr. Der Dienst befindet sich jetzt in der Phase der abgeschlossenen Beta-Tests, aber Sie können Zugriff anfordern, und wir geben ihn Ihnen sehr schnell.

Haftungsausschluss: Ich bin CTO von Polidea und Co-Creator des Dienstes.




Vielen Dank, dass die Ressourcen in mir helfen, diese Antwort zu finden.

Sie können Ihre Android Absturzberichte direkt in Ihre E-Mail finden . Remember Sie müssen Ihre E-Mail in CustomExceptionHandler-Klasse setzen .

public static String sendErrorLogsTo = "tushar.pandey@virtualxcellence.com" ;

Schritte erforderlich:

1.) in onCreate Ihrer Aktivität verwenden Sie diesen Abschnitt Ihres Codes.

    if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
        Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(this));
    }   

2.) benutze diese überschriebene Version der CustomExceptionHandler Klasse von (rrainn), laut meinem phpscript.

package com.vxmobilecomm.activity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.AsyncTask;
import android.util.Log;

public class CustomExceptionHandler implements UncaughtExceptionHandler {

    private UncaughtExceptionHandler defaultUEH;
    public static String sendErrorLogsTo = "tushar.pandey@virtualxcellence.com" ;

    Activity activity;

    public CustomExceptionHandler(Activity activity) {
        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
        this.activity = activity;
    }

    public void uncaughtException(Thread t, Throwable e) {

        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        e.printStackTrace(printWriter);
        String stacktrace = result.toString();
        printWriter.close();
        String filename = "error" + System.nanoTime() + ".stacktrace";

        Log.e("Hi", "url != null");
        sendToServer(stacktrace, filename);

        StackTraceElement[] arr = e.getStackTrace();
        String report = e.toString() + "\n\n";
        report += "--------- Stack trace ---------\n\n";
        for (int i = 0; i < arr.length; i++) {
            report += "    " + arr[i].toString() + "\n";
        }
        report += "-------------------------------\n\n";

        report += "--------- Cause ---------\n\n";
        Throwable cause = e.getCause();
        if (cause != null) {
            report += cause.toString() + "\n\n";
            arr = cause.getStackTrace();
            for (int i = 0; i < arr.length; i++) {
                report += "    " + arr[i].toString() + "\n";
            }
        }
        report += "-------------------------------\n\n";

        defaultUEH.uncaughtException(t, e);
    }

    private void sendToServer(String stacktrace, String filename) {
        AsyncTaskClass async = new AsyncTaskClass(stacktrace, filename,
                getAppLable(activity));
        async.execute("");
    }

    public String getAppLable(Context pContext) {
        PackageManager lPackageManager = pContext.getPackageManager();
        ApplicationInfo lApplicationInfo = null;
        try {
            lApplicationInfo = lPackageManager.getApplicationInfo(
                    pContext.getApplicationInfo().packageName, 0);
        } catch (final NameNotFoundException e) {
        }
        return (String) (lApplicationInfo != null ? lPackageManager
                .getApplicationLabel(lApplicationInfo) : "Unknown");
    }

    public class AsyncTaskClass extends AsyncTask<String, String, InputStream> {
        InputStream is = null;
        String stacktrace;
        final String filename;
        String applicationName;

        AsyncTaskClass(final String stacktrace, final String filename,
                String applicationName) {
            this.applicationName = applicationName;
            this.stacktrace = stacktrace;
            this.filename = filename;
        }

        @Override
        protected InputStream doInBackground(String... params) 
        { 
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(
                    "http://suo-yang.com/books/sendErrorLog/sendErrorLogs.php?");

            Log.i("Error", stacktrace);

            try {
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
                        6);

                nameValuePairs.add(new BasicNameValuePair("data", stacktrace));
                nameValuePairs.add(new BasicNameValuePair("to",sendErrorLogsTo));
                nameValuePairs.add(new BasicNameValuePair("subject",applicationName));

                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

                HttpResponse response = httpclient.execute(httppost);

                HttpEntity entity1 = response.getEntity();

                BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(
                        entity1);

                is = bufHttpEntity.getContent();

            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return is;
        }

        @Override
        protected void onPostExecute(InputStream result) {
            super.onPostExecute(result);

            Log.e("Stream Data", getStringFromInputStream(is));
        }
    }

    // convert InputStream to String
    private static String getStringFromInputStream(InputStream is) {

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();

        String line;
        try {

            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb.toString();

    }
}



Ok, nun habe ich mir die mitgelieferten Beispiele von Rrainn und Soonil angeschaut und eine Lösung gefunden, die die Fehlerbehandlung nicht durcheinander bringt.

Ich habe den CustomExceptionHandler so modifiziert, dass er den ursprünglichen UncaughtExceptionHandler aus dem Thread speichert, mit dem wir den neuen assoziieren. Am Ende der neuen "uncaughtException" - Methode rufe ich einfach die alte Funktion mit dem gespeicherten UncaughtExceptionHandler auf.

In der DefaultExceptionHandler-Klasse benötigen Sie etw. so was:

public class DefaultExceptionHandler implements UncaughtExceptionHandler{
  private UncaughtExceptionHandler mDefaultExceptionHandler;

  //constructor
  public DefaultExceptionHandler(UncaughtExceptionHandler pDefaultExceptionHandler)
  {
       mDefaultExceptionHandler= pDefaultExceptionHandler;
  }
  public void uncaughtException(Thread t, Throwable e) {       
        //do some action like writing to file or upload somewhere         

        //call original handler  
        mStandardEH.uncaughtException(t, e);        

        // cleanup, don't know if really required
        t.getThreadGroup().destroy();
  }
}

Mit dieser Änderung am Code unter http://code.google.com/p/android-remote-stacktrace Sie eine gute Arbeitsgrundlage für die Anmeldung des Feldes auf Ihrem Webserver oder auf der SD-Karte.




Ich habe meine eigene Version hier gemacht: http://androidblogger.blogspot.com/2009/12/how-to-improve-your-application-crash.html

Es ist im Grunde das Gleiche, aber ich verwende eine E-Mail anstelle einer http-Verbindung, um den Bericht zu senden, und, was noch wichtiger ist, habe ich meinem Bericht einige Informationen wie Anwendungsversion, Betriebssystemversion, Telefonmodell oder verfügbares Gedächtnis hinzugefügt. .




Es gibt diese Android-Bibliothek namens Sherlock . Sie erhalten den vollständigen Absturzbericht mit Informationen zu Geräten und Anwendungen. Immer wenn ein Absturz auftritt, wird eine Benachrichtigung in der Benachrichtigungsleiste angezeigt und beim Klicken auf die Benachrichtigung werden die Absturzdetails geöffnet. Sie können auch Absturzdetails mit anderen über E-Mail oder andere Freigabeoptionen teilen.

Installation

android {
    dataBinding {
      enabled = true
    }
}

compile('com.github.ajitsing:sherlock:1.0.0@aar') {
    transitive = true
}

Demo




Ich sehe, dass die Frage zu alt ist und hoffe, dass meine Antwort hilfreich für andere ist, die dasselbe Problem haben ...

Gib Crashlytics einen Versuch. Es gibt einen tiefen Einblick in alle Abstürze auf allen Geräten mit Ihrer Anwendung und senden Sie eine Benachrichtigung per E-Mail .. Und das Beste ist, es ist völlig kostenlos zu verwenden ..






Related