Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read projectPackages array when serialising error reports #451

Merged
merged 5 commits into from
Apr 4, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
* Prevent NPE occurring when calling resumeSession()
[#444](https://github.com/bugsnag/bugsnag-android/pull/444)

* Read projectPackages array when serialising error reports
[#451](https://github.com/bugsnag/bugsnag-android/pull/451)

## 4.12.0 (2019-02-27)

### Enhancements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ public void testShouldIgnore() {
assertTrue(config.shouldIgnoreClass(className));
}

@SuppressWarnings("deprecation")
@Test
public void testInProject() {
// Shouldn't be inProject if projectPackages hasn't been set
Expand Down
29 changes: 19 additions & 10 deletions sdk/src/androidTest/java/com/bugsnag/android/StacktraceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,21 @@ public class StacktraceTest {

private Configuration config;
private Throwable exception;
private String[] projectPackages;

/**
* Creates an initial exception
*/
@Before
public void setUp() throws Exception {
config = new Configuration("api-key");
exception = new RuntimeException("oops");
projectPackages = config.getProjectPackages();
}

@Test
public void testBasicException() throws JSONException, IOException {
Stacktrace stacktrace = new Stacktrace(config, exception.getStackTrace());
Stacktrace stacktrace = new Stacktrace(exception.getStackTrace(), projectPackages);
JSONArray stacktraceJson = streamableToJsonArray(stacktrace);

JSONObject firstFrame = (JSONObject) stacktraceJson.get(0);
Expand All @@ -50,7 +55,7 @@ public void testBasicException() throws JSONException, IOException {
public void testInProject() throws JSONException, IOException {
config.setProjectPackages(new String[]{"com.bugsnag.android"});

Stacktrace stacktrace = new Stacktrace(config, exception.getStackTrace());
Stacktrace stacktrace = new Stacktrace(exception.getStackTrace(), projectPackages);
JSONArray stacktraceJson = streamableToJsonArray(stacktrace);

JSONObject firstFrame = (JSONObject) stacktraceJson.get(0);
Expand All @@ -62,27 +67,31 @@ public void testStacktraceTrimming() throws Throwable {
List<StackTraceElement> elements = new ArrayList<>();

for (int k = 0; k < 1000; k++) {
elements.add(new StackTraceElement("SomeClass", "someMethod", "someFile", k));
elements.add(new StackTraceElement("SomeClass",
"someMethod", "someFile", k));
}

StackTraceElement[] ary = new StackTraceElement[elements.size()];
Stacktrace stacktrace = new Stacktrace(config, elements.toArray(ary));
Stacktrace stacktrace = new Stacktrace(elements.toArray(ary), projectPackages);
JSONArray jsonArray = streamableToJsonArray(stacktrace);
assertEquals(200, jsonArray.length());
}

@Test
public void testClassNameResolution() throws JSONException, IOException {
JSONArray stacktraceJson = streamableToJsonArray(
new Stacktrace(config, new StackTraceElement[] {
new StackTraceElement("SomeClass", "someMethod", "someFile", 12)}));
StackTraceElement[] stackTraceElements = {
new StackTraceElement("SomeClass", "someMethod", "someFile", 12)};
Stacktrace stacktrace = new Stacktrace(stackTraceElements, projectPackages);
JSONArray stacktraceJson = streamableToJsonArray(stacktrace);

JSONObject frame = (JSONObject) stacktraceJson.get(0);
assertEquals("SomeClass.someMethod", frame.get("method"));

stacktraceJson = streamableToJsonArray(
new Stacktrace(config, new StackTraceElement[] {
new StackTraceElement("", "someMethod", "someFile", 12)}));
StackTraceElement stackTraceElement = new StackTraceElement("",
"someMethod", "someFile", 12);
Stacktrace stacktrace1 = new Stacktrace(
new StackTraceElement[]{stackTraceElement}, projectPackages);
stacktraceJson = streamableToJsonArray(stacktrace1);

frame = (JSONObject) stacktraceJson.get(0);
assertEquals("someMethod", frame.get("method"));
Expand Down
2 changes: 2 additions & 0 deletions sdk/src/main/java/com/bugsnag/android/Bugsnag.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ public static void setNotifyReleaseStages(@Nullable final String... notifyReleas
* By default, we'll mark the current package name as part of you app.
*
* @param projectPackages a list of package names
* @deprecated use {{@link Configuration#setProjectPackages(String[])}} instead
*/
@Deprecated
public static void setProjectPackages(@Nullable final String... projectPackages) {
getClient().setProjectPackages(projectPackages);
}
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/main/java/com/bugsnag/android/CachedThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void toStream(@NonNull JsonStream writer) throws IOException {
writer.name("id").value(id);
writer.name("name").value(name);
writer.name("type").value(type);
writer.name("stacktrace").value(new Stacktrace(config, frames));
writer.name("stacktrace").value(new Stacktrace(frames, config.getProjectPackages()));
if (isErrorReportingThread) {
writer.name("errorReportingThread").value(true);
}
Expand Down
2 changes: 2 additions & 0 deletions sdk/src/main/java/com/bugsnag/android/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,9 @@ public void setNotifyReleaseStages(@Nullable String... notifyReleaseStages) {
* By default, we'll mark the current package name as part of you app.
*
* @param projectPackages a list of package names
* @deprecated use {{@link Configuration#setProjectPackages(String[])}} instead
*/
@Deprecated
public void setProjectPackages(@Nullable String... projectPackages) {
config.setProjectPackages(projectPackages);
}
Expand Down
12 changes: 3 additions & 9 deletions sdk/src/main/java/com/bugsnag/android/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -754,16 +754,10 @@ protected void beforeRecordBreadcrumb(@NonNull BeforeRecordBreadcrumb beforeReco
* @param className the class to check
* @return true if the class should be considered in the project else false
*/
@Deprecated
fractalwrench marked this conversation as resolved.
Show resolved Hide resolved
protected boolean inProject(@NonNull String className) {
if (projectPackages != null) {
for (String packageName : projectPackages) {
if (packageName != null && className.startsWith(packageName)) {
return true;
}
}
}

return false;
Stacktrace stacktrace = new Stacktrace(new StackTraceElement[]{}, projectPackages);
return stacktrace.inProject(className);
fractalwrench marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
13 changes: 12 additions & 1 deletion sdk/src/main/java/com/bugsnag/android/Error.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class Error implements JsonStream.Streamable {

@NonNull
final Configuration config;
private final String[] projectPackages;
private String[] projectPackages;
private final Exceptions exceptions;
private Breadcrumbs breadcrumbs;
private final Throwable exception;
Expand Down Expand Up @@ -382,6 +382,17 @@ Session getSession() {
return session;
}

String[] getProjectPackages() {
return projectPackages;
}

void setProjectPackages(String[] projectPackages) {
this.projectPackages = projectPackages;
if (exceptions != null) {
exceptions.setProjectPackages(projectPackages);
}
}

static class Builder {
private final Configuration config;
private final Throwable exception;
Expand Down
30 changes: 19 additions & 11 deletions sdk/src/main/java/com/bugsnag/android/ErrorReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -39,6 +40,7 @@ static Error readError(@NonNull Configuration config, @NonNull File errorFile)
ThreadState threadState = null;
Breadcrumbs crumbs = null;
ArrayList<String> severityReasonValues = null;
List<String> projectPackages = Collections.emptyList();
boolean unhandled = false;

reader = new JsonReader(new FileReader(errorFile));
Expand All @@ -57,6 +59,9 @@ static Error readError(@NonNull Configuration config, @NonNull File errorFile)
case "device":
deviceData = jsonObjectToMap(reader);
break;
case "projectPackages":
projectPackages = jsonArrayToList(reader);
break;
case "exceptions":
exceptions = readExceptions(config, reader);
break;
Expand Down Expand Up @@ -97,9 +102,11 @@ static Error readError(@NonNull Configuration config, @NonNull File errorFile)
: null;
HandledState handledState = new HandledState(severityReasonValues.get(0), severity,
unhandled, severityReasonAttribute);

Error error = new Error(config, exceptions.getException(), handledState, severity,
session, threadState);
error.getExceptions().setExceptionType(exceptions.getExceptionType());
error.setProjectPackages(projectPackages.toArray(new String[]{}));
error.setUser(user);
error.setContext(context);
error.setGroupingHash(groupingHash);
Expand Down Expand Up @@ -445,11 +452,11 @@ private static Map<String, Object> jsonObjectToMap(JsonReader reader) throws IOE
return data;
}

private static List<Object> jsonArrayToList(JsonReader reader) throws IOException {
List<Object> objects = new ArrayList<>();
private static <T> List<T> jsonArrayToList(JsonReader reader) throws IOException {
List<T> objects = new ArrayList<>();
reader.beginArray();
while (reader.hasNext()) {
Object value = coerceSerializableFromJSON(reader);
T value = coerceSerializableFromJSON(reader);
if (value != null) {
objects.add(value);
}
Expand All @@ -458,26 +465,27 @@ private static List<Object> jsonArrayToList(JsonReader reader) throws IOExceptio
return objects;
}

private static Object coerceSerializableFromJSON(JsonReader reader) throws IOException {
@SuppressWarnings("unchecked")
private static <T> T coerceSerializableFromJSON(JsonReader reader) throws IOException {
switch (reader.peek()) {
case BEGIN_OBJECT:
return jsonObjectToMap(reader);
return (T) jsonObjectToMap(reader);
case STRING:
return reader.nextString();
return (T) reader.nextString();
case BOOLEAN:
return reader.nextBoolean();
return (T)(Boolean) reader.nextBoolean();
case NUMBER:
try {
return reader.nextInt();
return (T)(Integer) reader.nextInt();
} catch (NumberFormatException ex) {
try {
return reader.nextLong();
return (T)(Long) reader.nextLong();
} catch (NumberFormatException ex2) {
return reader.nextDouble();
return (T)(Double) reader.nextDouble();
}
}
case BEGIN_ARRAY:
return jsonArrayToList(reader);
return (T) jsonArrayToList(reader);
default:
return null;
}
Expand Down
14 changes: 13 additions & 1 deletion sdk/src/main/java/com/bugsnag/android/Exceptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import android.support.annotation.NonNull;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
* Unwrap and serialize exception information and any "cause" exceptions.
Expand All @@ -11,11 +13,13 @@ class Exceptions implements JsonStream.Streamable {
private final Configuration config;
private final Throwable exception;
private String exceptionType;
private String[] projectPackages;

Exceptions(Configuration config, Throwable exception) {
this.config = config;
this.exception = exception;
exceptionType = Configuration.DEFAULT_EXCEPTION_TYPE;
projectPackages = config.getProjectPackages();
}

@Override
Expand Down Expand Up @@ -51,6 +55,14 @@ void setExceptionType(@NonNull String type) {
exceptionType = type;
}

String[] getProjectPackages() {
return projectPackages;
}

void setProjectPackages(String[] projectPackages) {
this.projectPackages = projectPackages;
}

/**
* Get the class name from the exception contained in this Error report.
*/
Expand All @@ -71,7 +83,7 @@ private void exceptionToStream(@NonNull JsonStream writer,
writer.name("message").value(message);
writer.name("type").value(exceptionType);

Stacktrace stacktrace = new Stacktrace(config, frames);
Stacktrace stacktrace = new Stacktrace(frames, projectPackages);
writer.name("stacktrace").value(stacktrace);
writer.endObject();
}
Expand Down
22 changes: 18 additions & 4 deletions sdk/src/main/java/com/bugsnag/android/Stacktrace.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import android.support.annotation.NonNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* Serialize an exception stacktrace and mark frames as "in-project"
Expand All @@ -12,12 +15,14 @@ class Stacktrace implements JsonStream.Streamable {

private static final int STACKTRACE_TRIM_LENGTH = 200;

final Configuration config;
private final List<String> projectPackages = new ArrayList<>();
fractalwrench marked this conversation as resolved.
Show resolved Hide resolved
final StackTraceElement[] stacktrace;

Stacktrace(Configuration config, StackTraceElement[] stacktrace) {
this.config = config;
Stacktrace(StackTraceElement[] stacktrace, String[] projectPackages) {
this.stacktrace = stacktrace;
if (projectPackages != null) {
this.projectPackages.addAll(Arrays.asList(projectPackages));
}
}

@Override
Expand All @@ -36,7 +41,7 @@ public void toStream(@NonNull JsonStream writer) throws IOException {
writer.name("file").value(el.getFileName() == null ? "Unknown" : el.getFileName());
writer.name("lineNumber").value(el.getLineNumber());

if (config.inProject(el.getClassName())) {
if (inProject(el.getClassName())) {
writer.name("inProject").value(true);
}

Expand All @@ -48,4 +53,13 @@ public void toStream(@NonNull JsonStream writer) throws IOException {

writer.endArray();
}

boolean inProject(String className) {
for (String packageName : projectPackages) {
if (packageName != null && className.startsWith(packageName)) {
return true;
}
}
return false;
}
}