Androidアプリケーションからクラッシュデータ(少なくともスタックトレース)を取得するにはどうすればよいですか?少なくともケーブルで取得している自分のデバイスで作業しているときは、理想的には、野生で実行しているアプリケーションのインスタンスから、それを改善してより強固にすることができます。
Androidアプリケーションからクラッシュデータ(少なくともスタックトレース)を取得するにはどうすればよいですか?少なくともケーブルで取得している自分のデバイスで作業しているときは、理想的には、野生で実行しているアプリケーションのインスタンスから、それを改善してより強固にすることができます。
回答:
ACRA(Android向けアプリケーションクラッシュレポート)ライブラリを試すことができます。
ACRAは、AndroidアプリケーションがクラッシュレポートをGoogleDocフォームに自動的に投稿できるようにするライブラリです。これは、Androidアプリケーション開発者がクラッシュまたは誤った動作をしたときにアプリケーションからデータを取得できるようにすることを目的としています。
アプリへのインストールは簡単で、高度な設定が可能で、サーバースクリプトをホストする必要はありません。レポートはGoogleドキュメントのスプレッドシートに送信されます。
サンプルアプリケーションとデバッグの目的で、デバイスのSDカードにスタックトレースを書き込んだり、サーバーにアップロードしたりできる簡単なソリューションを使用しています。このソリューションは、プロジェクトのandroid-remote-stacktrace(具体的には、デバイスへの保存とサーバーへのアップロードの部分)に触発されており、Soonilが述べた問題を解決すると思います。最適ではありませんが、機能し、本番アプリケーションで使用する場合は改善できます。スタックトレースをサーバーにアップロードする場合は、phpスクリプト(index.php
)を使用してそれらを表示できます。興味がある場合は、以下のすべてのソースを見つけることができます-アプリケーション用の1つのJavaクラスと、アップロードされたスタックトレースをホストするサーバー用の2つのオプションのphpスクリプト。
コンテキスト(メインのアクティビティなど)で、
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");
?>
HttpPost httpPost = new HttpPost(url);
Honeycomb以降をターゲットにしている場合は、非同期タスク(またはハンドラー...別のスレッド)にいる必要があります
[BugSense]の 理由:別のURLへのスパムリダイレクトも試すことができます。BugSenseはすべてのクラッシュレポートを収集して分析し、有意義で視覚的なレポートを提供します。それは無料で、統合するためのコードはたった1行です。
免責事項:私は共同創設者です
Android 2.2では、Androidマーケットアプリケーションからクラッシュレポートを自動的に取得できるようになりました。
Androidマーケットアプリの新しいバグレポート機能により、デベロッパーはユーザーからクラッシュレポートとフリーズレポートを受け取ることができます。レポートは、パブリッシャーアカウントにログインすると利用できます。
http://developer.android.com/sdk/android-2.2-highlights.html
でこれらの例外を処理することは可能ですが、これはThread.setDefaultUncaughtExceptionHandler()
Androidの例外処理方法を混乱させるようです。私はこの性質のハンドラーを使用しようとしました:
private class ExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread thread, Throwable ex){
Log.e(Constants.TAG, "uncaught_exception_handler: uncaught exception in thread " + thread.getName(), ex);
//hack to rethrow unchecked exceptions
if(ex instanceof RuntimeException)
throw (RuntimeException)ex;
if(ex instanceof Error)
throw (Error)ex;
//this should really never happen
Log.e(Constants.TAG, "uncaught_exception handler: unable to rethrow checked exception");
}
}
ただし、例外を再スローしても、目的の動作を得ることができませんでした。つまり、例外をログに記録しながら、発生したコンポーネントをAndroidがシャットダウンできるようにしたため、しばらくして諦めました。
Constants.TAG
Androidのフレームワークの一部?初めて見ました。見つけられないようです。
質問が古すぎるようです。私の回答が同じ問題を抱えている他の人に役立つことを願っています...
与えるCrashlyticsに試して。それはあなたのアプリケーションを持っているすべてのデバイスでのすべてのクラッシュの詳細な洞察を与え、電子メールであなたに通知を送信します。そして最良の部分は完全に無料で使用できます。
さて、私はrrainnとSoonilから提供されたサンプルを見て、エラー処理を台無しにしないソリューションを見つけました。
CustomExceptionHandlerを変更して、新しいものに関連付けるスレッドからの元のUncaughtExceptionHandlerを格納するようにしました。新しい "uncaughtException"-メソッドの最後に、保存されたUncaughtExceptionHandlerを使用して古い関数を呼び出すだけです。
DefaultExceptionHandlerクラスでは、sthが必要です。このような:
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();
}
}
http://code.google.com/p/android-remote-stacktraceのコードにその変更を加える と、フィールドにWebサーバーまたはsdカードにログインするための適切な作業ベースが得られます。
Google Play Developers Consoleは実際には、クラッシュしてレポートを送信したアプリからのスタックトレースを提供します。また、情報を確認するのに役立つ非常に優れたグラフもあります。以下の例を参照してください:
私はAndroidアプリとiOSアプリにCrittercismを使用してきました- テククランチでそれらについて聞いたことがあります。これまでのところ、かなり満足しています。
ここで自分のバージョンを作成しました:http : //androidblogger.blogspot.com/2009/12/how-to-improve-your-application-crash.html
基本的には同じですが、レポートの送信にhttp接続ではなくメールを使用しています。さらに重要なのは、アプリケーションのバージョン、OSのバージョン、電話のモデル、使用可能なメモリなどの情報をレポートに追加したことです。 。
これを使用して、例外の詳細をキャッチします。
String stackTrace = Log.getStackTraceString(exception);
これをデータベースに保存し、ログを維持します。
ライブラリだけでなく、サービス全体(シンプル)を使用することもできます。当社はそのためのサービスをリリースしました:http : //apphance.com。
5分で追加および統合できるシンプルな.jarライブラリ(Android用)があり、ライブラリはクラッシュ情報だけでなく、実行中のアプリケーションからのログも収集し、テスターがデバイスから直接問題を報告できるようにします-コンテキスト全体(デバイスのローテーション、Wi-Fiに接続されているかどうかに関係なく)。アプリケーションのセッション、クラッシュ、ログ、統計などを追跡できる、非常に便利で便利なWebパネルを使用してログを確認できます。現在、サービスはクローズドベータテスト段階にありますが、アクセスをリクエストしていただければ、すぐに提供します。
免責事項:私はPolideaのCTOであり、サービスの共同作成者です。
に存在するリソースに感謝 Stackoverflow
この答えを見つけるのを手伝ってくれたします。
あなたは見つけることができますあなたの電子メールに直接ごリモートでAndroidのクラッシュレポートを。メールをCustomExceptionHandlerクラス内に配置する必要があることに注意してください。
public static String sendErrorLogsTo = "tushar.pandey@virtualxcellence.com" ;
必要な手順:
1)アクティビティのonCreateで、コードのこのセクションを使用します。
if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(this));
}
2)私のphpscriptによれば、このオーバーライドされたバージョンのCustomExceptionHandlerクラス(rrainn)を使用します。
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();
}
}
現在、Firebase Crashレポートは非常に人気があり、使いやすくなっています。詳細については、次のリンクを参照してください: Firebase Crash Reporting
それがあなたを助けることを願っています。
これは非常に野蛮ですが、logcatをどこでも実行することが可能であるため、迅速かつダーティーなハックは、任意のキャッチブロックに追加することです getRuntime().exec("logcat >> /sdcard/logcat.log");
ファブリックと呼ばれるツールがあります。これはクラッシュ分析ツールであり、アプリケーションがライブでデプロイされているときや開発中にクラッシュレポートを取得できます。このツールをアプリケーションに追加するのも簡単でした。アプリケーションがクラッシュすると、そのクラッシュのレポートをfabric.ioダッシュボードから表示できます。レポートは自動的にキャッチされました。ユーザーに許可を求めることはありません。バグ/クラッシュレポートを送信するかどうか。そして、これは完全に無料です... https://get.fabric.io/
Google Firebaseは、スマートフォンでクラッシュ/エラーデータを提供するGoogleの最新(2016)の方法です。それをbuild.gradleファイルに含めます。
compile 'com.google.firebase:firebase-crash:9.0.0'
致命的なクラッシュはユーザー入力を必要とせずに自動的にログに記録され、致命的でないクラッシュやその他のイベントをログに記録することもできます。
try
{
}
catch(Exception ex)
{
FirebaseCrash.report(new Exception(ex.toString()));
}
シャーロックと呼ばれるこのAndroidライブラリがありますます。デバイスとアプリケーションの情報とともに、クラッシュの完全なレポートを提供します。クラッシュが発生すると、通知バーに通知が表示され、通知をクリックすると、クラッシュの詳細が開きます。メールやその他の共有オプションを使用して、クラッシュの詳細を他のユーザーと共有することもできます。
取り付け
android {
dataBinding {
enabled = true
}
}
compile('com.github.ajitsing:sherlock:1.0.0@aar') {
transitive = true
}
デモ
このページの回答の多くは役に立ちますが、古くなる可能性があります。AppBrain Webサイトは、最新の最も一般的なクラッシュレポートソリューションを見つけることができる統計を集計します。
この写真を投稿した時点で、Crashlyticsはアプリの5.24%とインストールの12.38%で使用されていることがわかります。
私たちは社内で自社開発したシステムを使用しており、非常に役立ちます。これは、サーバーとサーバーにクラッシュレポートを送信し、レポートを受信して分析を行うAndroidライブラリです。サーバーは、例外名、スタックトレース、メッセージによって例外をグループ化します。修正が必要な最も重要な問題を特定するのに役立ちます。現在、私たちのサービスはパブリックベータ版ですので、どなたでもお試しください。http://watchcat.coでアカウントを作成するか、デモアクセスhttp://watchcat.co/reports/index.php?demoを使用して、その仕組みを確認することができます。
エラーレポートを追跡する優れたWebアプリケーションがもう1つ見つかりました。
構成するステップの数が少ない。
Mint.initAndStartSession(YourActivity.this, "api_key");
android { ... repositories { maven { url "https://mint.splunk.com/gradle/"} } ... } dependencies { ... compile "com.splunk.mint:mint:4.4.0" ... }
Mint.initAndStartSession(YourActivity.this、 "api_key");
それでおしまい。ログインしてアプリケーションダッシュボードに移動すると、すべてのエラーレポートが表示されます。
それが誰かを助けることを願っています。
代替のクラッシュレポート/例外追跡サービスについては、Raygun.ioをチェックしてください。Androidクラッシュを処理するための素晴らしいロジックがたくさんあります。これには、アプリにプラグインするときの適切なユーザーエクスペリエンスが含まれます(メインアクティビティの2行のコードといくつかのコード) AndroidManifestに貼り付けられたXMLの行)。
アプリがクラッシュすると、スタックトレース、ハード/ソフトウェアの環境データ、ユーザートラッキング情報、指定したカスタムデータなどを自動的に取得します。UIスレッドをブロックせずに、APIに非同期に投稿し、キャッシュします。利用可能なネットワークがない場合は、ディスクへ。
免責事項:私はAndroidプロバイダーを構築しました:)
Googleフォームをバックエンドとして使用してACRA https://github.com/ACRA/acraの使用を開始したばかりで、セットアップと使用が非常に簡単で、デフォルトです。
しかし、Googleフォームへのレポートの送信は廃止される予定です(その後削除されます): https : //plus.google.com/118444843928759726538/posts/GTTgsrEQdN6 https://github.com/ACRA/acra/wiki/Notice-on-Google -Form-Spreadsheet-usage
とにかく、あなた自身の送信者を定義することが可能です https://github.com/ACRA/acra/wiki/AdvancedUsage#wiki-Implementing_your_own_sender あなたは、たとえば電子メールの送信者に試してみることができます。
最小限の労力で、バグセンスにレポートを送信することが可能です:http ://www.bugsense.com/docs/android#acra
NBバグセンス無料アカウントは500レポート/月に制限されています
党に遅れて、私は支持し、ACRAがすべての中で最高のオプションであると信じています。セットアップと構成が簡単です。ACRAを使用してクラッシュレポートを取得し、MandrillApを使用して自分のメールアドレスに同じメールを送信するために、あらゆる場所からの入力を含む詳細なガイドを作成しました。
投稿へのリンク:https : //androidician.wordpress.com/2015/03/29/sending-crash-reports-with-acra-over-email-using-mandrill/
github上のサンプルプロジェクトへのリンク:https : //github.com/ayushhgoyal/AcraSample
私はまさにこの目的のために設計したBugsnagの創設者の一人です。Bugsnagは、Androidアプリの未処理の例外を自動的にキャプチャし、ダッシュボードに送信します。ダッシュボードでは、修正の優先順位を付けて、診断情報に飛び込むことができます。
クラッシュレポートシステムを選択または構築する際に考慮すべきいくつかの重要な事項と、いくつかのコードスニペットを以下に示します。
Androidでのクラッシュ処理/レポートに関するいくつかのベストプラクティスを確認したい場合は、完全にオープンソースであるBugsnagのクラッシュレポートライブラリの完全なソースコードをチェックして、自由に分解して独自のアプリケーションで使用してください。
アプリが他のユーザーによってダウンロードされてリモートデバイスでクラッシュしている場合は、Androidエラー報告ライブラリ(このSOの投稿で参照されている)を確認することをお勧めします。自分のローカルデバイス上にある場合は、LogCatを使用できます。クラッシュが発生したときにデバイスがホストマシンに接続されていなかった場合でも、デバイスを接続してadb logcatコマンドを発行すると、logcatの履歴全体がダウンロードされます(少なくとも、バッファリングされているため、通常はログデータが不足しています)。 、それは無限ではありません)。これらのオプションのどちらかがあなたの質問に答えますか?そうでない場合、あなたが探しているものをもう少し明確にしようとすることができますか?
Flurry Analyticsは、クラッシュ情報、ハードウェアモデル、Androidバージョン、ライブアプリの使用統計を提供します。新しいSDKでは、より詳細なクラッシュ情報http://www.flurry.com/flurry-crash-analytics.htmlを提供しているようです。
Googleは実際に取得するクラッシュレポートの量を変更しました。以前は、手動で報告されたバグレポートしかありませんでした。
前回の開発者会議とAndroid Vitalsの導入以来、診断データの共有を可能にしたユーザーからのクラッシュレポートも得られます。
ユーザーが使用状況と診断データを自動的に共有することを選択したAndroidデバイスから収集されたすべてのクラッシュが表示されます。過去2か月のデータを利用できます。