I want to receive notification regarding crash report due to uncaught exception in my google analytics for my android app. I followed the steps given in https://developers.google.com/analytics/devguides/collection/android/v4/exceptions#parsing but still I dont receive any crash report. I had a runtime exception when my app runs. I added the code for ga_reportUncaughtException as true:
我希望收到有关崩溃报告的通知,因为我的Android应用程序的谷歌分析中未被捕获的异常。我按照https://developers.google.com/analytics/devguides/collection/android/v4/exceptions#parsing中给出的步骤操作,但我仍然没有收到任何崩溃报告。我的应用程序运行时出现运行时异常。我将ga_reportUncaughtException的代码添加为true:
true
真正
in my analytics.xml. Is there anything else I need to add in order to get hit in google analytics account. Please help!
在我的analytics.xml中。还有什么我需要添加才能在谷歌分析帐户中受到欢迎。请帮忙!
2 个解决方案
#1
6
There is an open issue in Analytics. I'm experiencing the same behavior but on real devices from API 10 to 19.
Analytics中存在一个未解决的问题。我在API 10到19的实际设备上遇到了相同的行为。
https://code.google.com/p/analytics-issues/issues/detail?id=443
https://code.google.com/p/analytics-issues/issues/detail?id=443
EDIT1: Removed question, just to answer the question described.
EDIT1:删除了问题,只是为了回答所描述的问题。
EDIT2: I tried to capture and send the exceptions using the Analytics ExceptionBuilder, but it didn't work.
EDIT2:我尝试使用Analytics ExceptionBuilder捕获并发送异常,但它不起作用。
It looks like the report is sent (at least LogCat is showing that the crash is reported), but it is not processed by Analytics.
看起来报告已发送(至少LogCat显示报告了崩溃),但Google不会处理它。
While Google replies to the issue, I'm using this workaround. I guess it is not the best solution and the code can be improved, but it works for me:
虽然Google回答了这个问题,但我正在使用此解决方法。我想这不是最好的解决方案,代码可以改进,但它适用于我:
-
I created a custom dimension in Analytics following this steps https://support.google.com/analytics/answer/2709829?hl=en
我按照以下步骤在Google Analytics中创建了自定义维度https://support.google.com/analytics/answer/2709829?hl=zh-CN
-
In my App, I created a custom exception handler, using the Analytics ExceptionReporter class. When an exception is caught, I get the stack trace and truncate it to 150 Bytes (Actually I'm getting only the first line of the stack and truncate it to 150 chars. I'm assuming that 1Char = 1 Byte). I have to truncate it, because it is the Max Lenght allowed by Analytics when sending custom dimensions values. The stack trace is stored in a Shared Preference instead of being sent. I tried to send it directly, but it does not work once the App has crashed.
在我的应用程序中,我使用Analytics ExceptionReporter类创建了一个自定义异常处理程序。当捕获异常时,我得到堆栈跟踪并将其截断为150字节(实际上我只得到堆栈的第一行并将其截断为150个字符。我假设1Char = 1个字节)。我必须截断它,因为它是发送自定义维度值时Google Analytics允许的最大长度。堆栈跟踪存储在共享首选项中,而不是发送。我试图直接发送它,但是一旦应用程序崩溃它就无法运行。
package com.company.package; import java.lang.Thread.UncaughtExceptionHandler; import android.content.Context; import com.google.android.gms.analytics.ExceptionParser; import com.google.android.gms.analytics.ExceptionReporter; import com.google.android.gms.analytics.GoogleAnalytics; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; public class GoogleAnalyticsTracker { private static Tracker mTracker; private static GoogleAnalytics mGa; private Context mContext; public GoogleAnalyticsTracker(Context context, int resource) { mContext = context; mGa = GoogleAnalytics.getInstance(context); mTracker = getTracker(resource); Thread.setDefaultUncaughtExceptionHandler(new AnalyticsExceptionReporter(mTracker, Thread.getDefaultUncaughtExceptionHandler(), context)); } synchronized Tracker getTracker(int xmlResource) { return mGa.newTracker(xmlResource); } public void sendScreenLabel(String screenLabel) { mTracker.setScreenName(screenLabel); mTracker.send(new HitBuilders.AppViewBuilder().build()); } public void sendCustomDimension(int index, String value) { mTracker.send(new HitBuilders.AppViewBuilder().setCustomDimension(index, value).build()); } private class AnalyticsExceptionReporter extends ExceptionReporter { public AnalyticsExceptionReporter(Tracker tracker, UncaughtExceptionHandler originalHandler, Context context) { super(tracker, originalHandler, context); setExceptionParser(new AnalyticsExceptionParser()); } @Override public void uncaughtException(Thread t, Throwable e) { String exceptionDescription = getExceptionParser().getDescription(t.getName(), e); //Add code to store the exception stack trace in shared preferences super.uncaughtException(t, e); } } private class AnalyticsExceptionParser implements ExceptionParser { @Override public String getDescription(String arg0, Throwable arg1) { StringBuilder exceptionFirsLine = new StringBuilder(); for (StackTraceElement element : arg1.getStackTrace()) { exceptionFirsLine.append(element.toString()); break; } //150 Bytes is the maximum allowed by Analytics for custom dimensions values. Assumed that 1 Byte = 1 Character (UTF-8) String exceptionDescription = exceptionFirsLine.toString(); if(exceptionDescription.length() > 150) exceptionDescription = exceptionDescription.substring(0, 149); return exceptionDescription; } } }
-
In the MainActivity when OnStart(), I check if there is any stored stack trace in the shared preferences. If so, I send the custom dimension and clear the shared preference.
在OnStart()的MainActivity中,我检查共享首选项中是否存在任何存储的堆栈跟踪。如果是,我发送自定义维度并清除共享首选项。
@Override protected void onStart() { super.onStart(); String exception = getExceptionFromSharedPreferences(this); if(exception != null && !exception.isEmpty()) { MainApplication.googleAnalyticsTracker.sendCustomDimension(1, exception); } clearExceptionFromSharedPreferences(this); }
-
Finally I created a custom report in Analytics
最后,我在Google Analytics中创建了自定义报告
EDIT 3:
编辑3:
I realized that I was sending only the fileName and lineNumber, but not the ExceptionName and the origin of the Exception in my package. I have improved the answer by adding code to also send that info.
我意识到我只发送了fileName和lineNumber,而不是我的包中的ExceptionName和Exception的来源。通过添加代码来发送该信息,我改进了答案。
private class AnalyticsExceptionParser implements ExceptionParser {
@Override
public String getDescription(String arg0, Throwable arg1) {
String exceptionDescription = getExceptionInfo(arg1, "", true) + getCauseExceptionInfo(arg1.getCause());
//150 Bytes is the maximum allowed by Analytics for custom dimensions values. Assumed that 1 Byte = 1 Character (UTF-8)
if(exceptionDescription.length() > 150)
exceptionDescription = exceptionDescription.substring(0, 150);
return exceptionDescription;
}
}
//#endregion
//#region PRIVATE METHODS
private String getCauseExceptionInfo(Throwable t) {
String causeDescription = "";
while(t != null && causeDescription.isEmpty()) {
causeDescription = getExceptionInfo(t, "com.myPackageName", false);
t = t.getCause();
}
return causeDescription;
}
private String getExceptionInfo(Throwable t, String packageName, boolean includeExceptionName) {
String exceptionName = "";
String fileName = "";
String lineNumber = "";
for (StackTraceElement element : t.getStackTrace()) {
String className = element.getClassName().toString().toLowerCase();
if(packageName.isEmpty() || (!packageName.isEmpty() && className.contains(packageName))){
exceptionName = includeExceptionName ? t.toString() : "";
fileName = element.getFileName();
lineNumber = String.valueOf(element.getLineNumber());
return exceptionName + "@" + fileName + ":" + lineNumber;
}
}
return "";
}
#2
1
From my experience you need to understand two things about crashes and exceptions in Google Analytics:
根据我的经验,您需要了解有关Google Analytics中崩溃和异常的两件事:
1) Only basic information is stored - Google Analytics will only save the name of the exception and the location (Code file and line number) where the exception was thrown. No information beyond that will be accessible to you on GA. This is definitely not ideal and if you wish to track the actual content of your exceptions (mainly the call stack), use Google Play or implement your own solution.
1)仅存储基本信息 - Google Analytics只会保存例外的名称以及抛出异常的位置(代码文件和行号)。 GA上无法访问您之外的任何信息。这绝对不是理想的,如果您希望跟踪例外的实际内容(主要是调用堆栈),请使用Google Play或实施您自己的解决方案。
2) Exceptions are not real-time. Exception information is collected and updated maybe once a day, so if you're experimenting with exceptions and you don't see them immediately, just give it time.
2)例外不是实时的。异常信息可能每天收集和更新一次,因此,如果您正在尝试异常而您没有立即看到它们,那就给它时间吧。
#1
6
There is an open issue in Analytics. I'm experiencing the same behavior but on real devices from API 10 to 19.
Analytics中存在一个未解决的问题。我在API 10到19的实际设备上遇到了相同的行为。
https://code.google.com/p/analytics-issues/issues/detail?id=443
https://code.google.com/p/analytics-issues/issues/detail?id=443
EDIT1: Removed question, just to answer the question described.
EDIT1:删除了问题,只是为了回答所描述的问题。
EDIT2: I tried to capture and send the exceptions using the Analytics ExceptionBuilder, but it didn't work.
EDIT2:我尝试使用Analytics ExceptionBuilder捕获并发送异常,但它不起作用。
It looks like the report is sent (at least LogCat is showing that the crash is reported), but it is not processed by Analytics.
看起来报告已发送(至少LogCat显示报告了崩溃),但Google不会处理它。
While Google replies to the issue, I'm using this workaround. I guess it is not the best solution and the code can be improved, but it works for me:
虽然Google回答了这个问题,但我正在使用此解决方法。我想这不是最好的解决方案,代码可以改进,但它适用于我:
-
I created a custom dimension in Analytics following this steps https://support.google.com/analytics/answer/2709829?hl=en
我按照以下步骤在Google Analytics中创建了自定义维度https://support.google.com/analytics/answer/2709829?hl=zh-CN
-
In my App, I created a custom exception handler, using the Analytics ExceptionReporter class. When an exception is caught, I get the stack trace and truncate it to 150 Bytes (Actually I'm getting only the first line of the stack and truncate it to 150 chars. I'm assuming that 1Char = 1 Byte). I have to truncate it, because it is the Max Lenght allowed by Analytics when sending custom dimensions values. The stack trace is stored in a Shared Preference instead of being sent. I tried to send it directly, but it does not work once the App has crashed.
在我的应用程序中,我使用Analytics ExceptionReporter类创建了一个自定义异常处理程序。当捕获异常时,我得到堆栈跟踪并将其截断为150字节(实际上我只得到堆栈的第一行并将其截断为150个字符。我假设1Char = 1个字节)。我必须截断它,因为它是发送自定义维度值时Google Analytics允许的最大长度。堆栈跟踪存储在共享首选项中,而不是发送。我试图直接发送它,但是一旦应用程序崩溃它就无法运行。
package com.company.package; import java.lang.Thread.UncaughtExceptionHandler; import android.content.Context; import com.google.android.gms.analytics.ExceptionParser; import com.google.android.gms.analytics.ExceptionReporter; import com.google.android.gms.analytics.GoogleAnalytics; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; public class GoogleAnalyticsTracker { private static Tracker mTracker; private static GoogleAnalytics mGa; private Context mContext; public GoogleAnalyticsTracker(Context context, int resource) { mContext = context; mGa = GoogleAnalytics.getInstance(context); mTracker = getTracker(resource); Thread.setDefaultUncaughtExceptionHandler(new AnalyticsExceptionReporter(mTracker, Thread.getDefaultUncaughtExceptionHandler(), context)); } synchronized Tracker getTracker(int xmlResource) { return mGa.newTracker(xmlResource); } public void sendScreenLabel(String screenLabel) { mTracker.setScreenName(screenLabel); mTracker.send(new HitBuilders.AppViewBuilder().build()); } public void sendCustomDimension(int index, String value) { mTracker.send(new HitBuilders.AppViewBuilder().setCustomDimension(index, value).build()); } private class AnalyticsExceptionReporter extends ExceptionReporter { public AnalyticsExceptionReporter(Tracker tracker, UncaughtExceptionHandler originalHandler, Context context) { super(tracker, originalHandler, context); setExceptionParser(new AnalyticsExceptionParser()); } @Override public void uncaughtException(Thread t, Throwable e) { String exceptionDescription = getExceptionParser().getDescription(t.getName(), e); //Add code to store the exception stack trace in shared preferences super.uncaughtException(t, e); } } private class AnalyticsExceptionParser implements ExceptionParser { @Override public String getDescription(String arg0, Throwable arg1) { StringBuilder exceptionFirsLine = new StringBuilder(); for (StackTraceElement element : arg1.getStackTrace()) { exceptionFirsLine.append(element.toString()); break; } //150 Bytes is the maximum allowed by Analytics for custom dimensions values. Assumed that 1 Byte = 1 Character (UTF-8) String exceptionDescription = exceptionFirsLine.toString(); if(exceptionDescription.length() > 150) exceptionDescription = exceptionDescription.substring(0, 149); return exceptionDescription; } } }
-
In the MainActivity when OnStart(), I check if there is any stored stack trace in the shared preferences. If so, I send the custom dimension and clear the shared preference.
在OnStart()的MainActivity中,我检查共享首选项中是否存在任何存储的堆栈跟踪。如果是,我发送自定义维度并清除共享首选项。
@Override protected void onStart() { super.onStart(); String exception = getExceptionFromSharedPreferences(this); if(exception != null && !exception.isEmpty()) { MainApplication.googleAnalyticsTracker.sendCustomDimension(1, exception); } clearExceptionFromSharedPreferences(this); }
-
Finally I created a custom report in Analytics
最后,我在Google Analytics中创建了自定义报告
EDIT 3:
编辑3:
I realized that I was sending only the fileName and lineNumber, but not the ExceptionName and the origin of the Exception in my package. I have improved the answer by adding code to also send that info.
我意识到我只发送了fileName和lineNumber,而不是我的包中的ExceptionName和Exception的来源。通过添加代码来发送该信息,我改进了答案。
private class AnalyticsExceptionParser implements ExceptionParser {
@Override
public String getDescription(String arg0, Throwable arg1) {
String exceptionDescription = getExceptionInfo(arg1, "", true) + getCauseExceptionInfo(arg1.getCause());
//150 Bytes is the maximum allowed by Analytics for custom dimensions values. Assumed that 1 Byte = 1 Character (UTF-8)
if(exceptionDescription.length() > 150)
exceptionDescription = exceptionDescription.substring(0, 150);
return exceptionDescription;
}
}
//#endregion
//#region PRIVATE METHODS
private String getCauseExceptionInfo(Throwable t) {
String causeDescription = "";
while(t != null && causeDescription.isEmpty()) {
causeDescription = getExceptionInfo(t, "com.myPackageName", false);
t = t.getCause();
}
return causeDescription;
}
private String getExceptionInfo(Throwable t, String packageName, boolean includeExceptionName) {
String exceptionName = "";
String fileName = "";
String lineNumber = "";
for (StackTraceElement element : t.getStackTrace()) {
String className = element.getClassName().toString().toLowerCase();
if(packageName.isEmpty() || (!packageName.isEmpty() && className.contains(packageName))){
exceptionName = includeExceptionName ? t.toString() : "";
fileName = element.getFileName();
lineNumber = String.valueOf(element.getLineNumber());
return exceptionName + "@" + fileName + ":" + lineNumber;
}
}
return "";
}
#2
1
From my experience you need to understand two things about crashes and exceptions in Google Analytics:
根据我的经验,您需要了解有关Google Analytics中崩溃和异常的两件事:
1) Only basic information is stored - Google Analytics will only save the name of the exception and the location (Code file and line number) where the exception was thrown. No information beyond that will be accessible to you on GA. This is definitely not ideal and if you wish to track the actual content of your exceptions (mainly the call stack), use Google Play or implement your own solution.
1)仅存储基本信息 - Google Analytics只会保存例外的名称以及抛出异常的位置(代码文件和行号)。 GA上无法访问您之外的任何信息。这绝对不是理想的,如果您希望跟踪例外的实际内容(主要是调用堆栈),请使用Google Play或实施您自己的解决方案。
2) Exceptions are not real-time. Exception information is collected and updated maybe once a day, so if you're experimenting with exceptions and you don't see them immediately, just give it time.
2)例外不是实时的。异常信息可能每天收集和更新一次,因此,如果您正在尝试异常而您没有立即看到它们,那就给它时间吧。