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

More open Event model #2060

Merged
merged 11 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from 10 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

* Include additional Intent information for Activity.onCreate breadcrumbs (action, categories, type, flags, id, extra keys)
[#2057](https://github.com/bugsnag/bugsnag-android/pull/2057)
* New APIs allowing new `Error`s, `Thread`s, and `Stackframe`s to be added to error reports (`Event`s)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* New APIs allowing new `Error`s, `Thread`s, and `Stackframe`s to be added to error reports (`Event`s)
* New APIs allowing new `Error`s, `Thread`s, and `Stackframe`s to be added to `Event`s

[#2060](https://github.com/bugsnag/bugsnag-android/pull/2060)

### Bug fixes

Expand Down
10 changes: 10 additions & 0 deletions bugsnag-android-core/api/bugsnag-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ public final class com/bugsnag/android/EndpointConfiguration {
}

public class com/bugsnag/android/Error : com/bugsnag/android/JsonStream$Streamable {
public fun addStackframe (Ljava/lang/String;Ljava/lang/String;J)Lcom/bugsnag/android/Stackframe;
public fun getErrorClass ()Ljava/lang/String;
public fun getErrorMessage ()Ljava/lang/String;
public fun getStacktrace ()Ljava/util/List;
Expand Down Expand Up @@ -350,11 +351,16 @@ public final class com/bugsnag/android/ErrorTypes {
}

public class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, com/bugsnag/android/JsonStream$Streamable, com/bugsnag/android/MetadataAware, com/bugsnag/android/UserAware {
public fun addError (Ljava/lang/String;Ljava/lang/String;)Lcom/bugsnag/android/Error;
public fun addError (Ljava/lang/String;Ljava/lang/String;Lcom/bugsnag/android/ErrorType;)Lcom/bugsnag/android/Error;
public fun addError (Ljava/lang/Throwable;)Lcom/bugsnag/android/Error;
public fun addFeatureFlag (Ljava/lang/String;)V
public fun addFeatureFlag (Ljava/lang/String;Ljava/lang/String;)V
public fun addFeatureFlags (Ljava/lang/Iterable;)V
public fun addMetadata (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V
public fun addMetadata (Ljava/lang/String;Ljava/util/Map;)V
public fun addThread (JLjava/lang/String;)Lcom/bugsnag/android/Thread;
public fun addThread (Ljava/lang/String;Ljava/lang/String;)Lcom/bugsnag/android/Thread;
public fun clearFeatureFlag (Ljava/lang/String;)V
public fun clearFeatureFlags ()V
public fun clearMetadata (Ljava/lang/String;)V
Expand All @@ -374,6 +380,8 @@ public class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, c
public fun getThreads ()Ljava/util/List;
public fun getUser ()Lcom/bugsnag/android/User;
public fun isUnhandled ()Z
public fun leaveBreadcrumb (Ljava/lang/String;)Lcom/bugsnag/android/Breadcrumb;
public fun leaveBreadcrumb (Ljava/lang/String;Lcom/bugsnag/android/BreadcrumbType;Ljava/util/Map;)Lcom/bugsnag/android/Breadcrumb;
public fun setApiKey (Ljava/lang/String;)V
public fun setContext (Ljava/lang/String;)V
public fun setGroupingHash (Ljava/lang/String;)V
Expand Down Expand Up @@ -762,6 +770,7 @@ public final class com/bugsnag/android/Telemetry : java/lang/Enum {
}

public class com/bugsnag/android/Thread : com/bugsnag/android/JsonStream$Streamable {
public fun addStackframe (Ljava/lang/String;Ljava/lang/String;J)Lcom/bugsnag/android/Stackframe;
public fun getErrorReportingThread ()Z
public fun getId ()Ljava/lang/String;
public fun getName ()Ljava/lang/String;
Expand Down Expand Up @@ -792,6 +801,7 @@ public final class com/bugsnag/android/Thread$State : java/lang/Enum {
}

public final class com/bugsnag/android/ThreadInternal : com/bugsnag/android/JsonStream$Streamable {
public final fun addStackframe (Ljava/lang/String;Ljava/lang/String;J)Lcom/bugsnag/android/Stackframe;
public final fun getId ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getStacktrace ()Ljava/util/List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ public List<Stackframe> getStacktrace() {
return impl.getStacktrace();
}

/**
* Add a new stackframe to the end of this Error returning the new Stackframe data object.
*/
@NonNull
public Stackframe addStackframe(@Nullable String method,
@Nullable String file,
long lineNumber) {
return impl.addStackframe(method, file, lineNumber);
}

@Override
public void toStream(@NonNull JsonStream stream) throws IOException {
impl.toStream(stream);
Expand All @@ -98,4 +108,4 @@ static List<Error> createError(@NonNull Throwable exc,
@NonNull Logger logger) {
return ErrorInternal.Companion.createError(exc, projectPackages, logger);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,30 @@ internal class ErrorInternal @JvmOverloads internal constructor(
var type: ErrorType = ErrorType.ANDROID
) : JsonStream.Streamable {

val stacktrace: List<Stackframe> = stacktrace.trace
val stacktrace: MutableList<Stackframe> = stacktrace.trace

fun addStackframe(method: String?, file: String?, lineNumber: Long): Stackframe {
val frame = Stackframe(method, file, lineNumber, null)
stacktrace.add(frame)
return frame
}

internal companion object {
fun createError(exc: Throwable, projectPackages: Collection<String>, logger: Logger): MutableList<Error> {
fun createError(
exc: Throwable,
projectPackages: Collection<String>,
logger: Logger
): MutableList<Error> {
return exc.safeUnrollCauses()
.mapTo(mutableListOf()) { currentEx ->
// Somehow it's possible for stackTrace to be null in rare cases
val stacktrace = currentEx.stackTrace ?: arrayOf<StackTraceElement>()
val trace = Stacktrace(stacktrace, projectPackages, logger)
val errorInternal =
ErrorInternal(currentEx.javaClass.name, currentEx.localizedMessage, trace)
val errorInternal = ErrorInternal(
currentEx.javaClass.name,
currentEx.localizedMessage,
trace
)

return@mapTo Error(errorInternal, logger)
}
Expand Down
101 changes: 95 additions & 6 deletions bugsnag-android-core/src/main/java/com/bugsnag/android/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ private void logNull(String property) {
}

/**
* The Throwable object that caused the event in your application.
*
* The {@link Throwable} object that caused the event in your application.
* <p>
* Manipulating this field does not affect the error information reported to the
* Bugsnag dashboard. Use {@link Event#getErrors()} to access and amend the representation of
* the error that will be sent.
Expand All @@ -66,7 +66,7 @@ public Throwable getOriginalError() {
* Information extracted from the {@link Throwable} that caused the event can be found in this
* field. The list contains at least one {@link Error} that represents the thrown object
* with subsequent elements in the list populated from {@link Throwable#getCause()}.
*
* <p>
* A reference to the actual {@link Throwable} object that caused the event is available
* through {@link Event#getOriginalError()} ()}.
*/
Expand All @@ -75,6 +75,35 @@ public List<Error> getErrors() {
return impl.getErrors();
}

/**
* Add a new error to this report and return its Error data. The new Error will appear at the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Add a new error to this report and return its Error data. The new Error will appear at the
* Add a new error to this event and return its Error data. The new Error will appear at the

* end of the {@link #getErrors() errors list}.
*/
@NonNull
public Error addError(@NonNull Throwable error) {
return impl.addError(error);
}

/**
* Add a new empty {@link ErrorType#ANDROID android} error to this report and return its Error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Add a new empty {@link ErrorType#ANDROID android} error to this report and return its Error
* Add a new empty {@link ErrorType#ANDROID android} event to this report and return its Error

* data. The new Error will appear at the end of the {@link #getErrors() errors list}.
*/
@NonNull
public Error addError(@NonNull String errorClass, @Nullable String errorMessage) {
return impl.addError(errorClass, errorMessage, ErrorType.ANDROID);
}

/**
* Add a new empty error to this report and return its Error data. The new Error will appear
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Add a new empty error to this report and return its Error data. The new Error will appear
* Add a new empty error to this event and return its Error data. The new Error will appear

* at the end of the {@link #getErrors() errors list}.
*/
@NonNull
public Error addError(@NonNull String errorClass,
@Nullable String errorMessage,
@NonNull ErrorType errorType) {
return impl.addError(errorClass, errorMessage, errorType);
}

/**
* If thread state is being captured along with the event, this field will contain a
* list of {@link Thread} objects.
Expand All @@ -84,6 +113,46 @@ public List<Thread> getThreads() {
return impl.getThreads();
}

/**
* Create, add and return a new empty {@link Thread} object to this event with a given id
* and name. This can be used to augment the report with thread data that would not be picked
* up as part of a normal report being generated (for example: native threads managed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* and name. This can be used to augment the report with thread data that would not be picked
* up as part of a normal report being generated (for example: native threads managed
* and name. This can be used to augment the event with thread data that would not be picked
* up as part of a normal event being generated (for example: native threads managed

* by cross-platform toolkits).
*
* @return a new Thread object of type {@link ErrorType#ANDROID} with no stacktrace
*/
@NonNull
public Thread addThread(@NonNull String id,
@NonNull String name) {
return impl.addThread(
id,
name,
ErrorType.ANDROID,
false,
Thread.State.RUNNABLE.getDescriptor()
);
}

/**
* Create, add and return a new empty {@link Thread} object to this event with a given id
* and name. This can be used to augment the report with thread data that would not be picked
* up as part of a normal report being generated (for example: native threads managed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* and name. This can be used to augment the report with thread data that would not be picked
* up as part of a normal report being generated (for example: native threads managed
* and name. This can be used to augment the event with thread data that would not be picked
* up as part of a normal event being generated (for example: native threads managed

* by cross-platform toolkits).
*
* @return a new Thread object of type {@link ErrorType#ANDROID} with no stacktrace
*/
@NonNull
public Thread addThread(long id,
@NonNull String name) {
return impl.addThread(
Long.toString(id),
name,
ErrorType.ANDROID,
false,
Thread.State.RUNNABLE.getDescriptor()
);
}

/**
* A list of breadcrumbs leading up to the event. These values can be accessed and amended
* if necessary. See {@link Breadcrumb} for details of the data available.
Expand All @@ -93,6 +162,26 @@ public List<Breadcrumb> getBreadcrumbs() {
return impl.getBreadcrumbs();
}

/**
* Add a new breadcrumb to this event and return its Breadcrumb object. The new breadcrumb
* will be added to the end of the {@link #getBreadcrumbs() breadcrumbs list} by this method.
*/
@NonNull
public Breadcrumb leaveBreadcrumb(@NonNull String message,
@NonNull BreadcrumbType type,
@Nullable Map<String, Object> metadata) {
return impl.leaveBreadcrumb(message, type, metadata);
}

/**
* Add a new breadcrumb to this event and return its Breadcrumb object. The new breadcrumb
* will be added to the end of the {@link #getBreadcrumbs() breadcrumbs list} by this# method.
*/
@NonNull
public Breadcrumb leaveBreadcrumb(@NonNull String message) {
return impl.leaveBreadcrumb(message, BreadcrumbType.MANUAL, null);
}

/**
* A list of feature flags active at the time of the event.
* See {@link FeatureFlag} for details of the data available.
Expand Down Expand Up @@ -167,7 +256,7 @@ public Severity getSeverity() {
* All events with the same grouping hash will be grouped together into one error. This is an
* advanced usage of the library and mis-using it will cause your events not to group properly
* in your dashboard.
*
* <p>
* As the name implies, this option accepts a hash of sorts.
*/
public void setGroupingHash(@Nullable String groupingHash) {
Expand All @@ -179,7 +268,7 @@ public void setGroupingHash(@Nullable String groupingHash) {
* All events with the same grouping hash will be grouped together into one error. This is an
* advanced usage of the library and mis-using it will cause your events not to group properly
* in your dashboard.
*
* <p>
* As the name implies, this option accepts a hash of sorts.
*/
@Nullable
Expand Down Expand Up @@ -388,7 +477,7 @@ public void setUnhandled(boolean unhandled) {
* using bugsnag-android-performance, but can also be set manually if required.
*
* @param traceId the ID of the trace the event occurred within
* @param spanId the ID of the span that the event occurred within
* @param spanId the ID of the span that the event occurred within
*/
public void setTraceCorrelation(@NonNull UUID traceId, long spanId) {
if (traceId != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.bugsnag.android.internal.InternalMetricsNoop
import com.bugsnag.android.internal.JsonHelper
import com.bugsnag.android.internal.TrimMetrics
import java.io.IOException
import java.util.Date
import java.util.regex.Pattern

internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, MetadataAware, UserAware {
Expand Down Expand Up @@ -324,4 +325,72 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata
override fun clearFeatureFlag(name: String) = featureFlags.clearFeatureFlag(name)

override fun clearFeatureFlags() = featureFlags.clearFeatureFlags()

fun addError(thrownError: Throwable?): Error {
if (thrownError == null) {
val newError = Error(
ErrorInternal("null", null, Stacktrace(ArrayList())),
logger
)
errors.add(newError)
return newError
} else {
val newErrors = Error.createError(thrownError, projectPackages, logger)
errors.addAll(newErrors)
return newErrors.first()
}
}

fun addError(errorClass: String?, errorMessage: String?, errorType: ErrorType?): Error {
val error = Error(
ErrorInternal(
errorClass.toString(),
errorMessage,
Stacktrace(ArrayList()),
errorType ?: ErrorType.ANDROID
),
logger
)
errors.add(error)
return error
}

fun addThread(
id: String?,
name: String?,
errorType: ErrorType,
isErrorReportingThread: Boolean,
state: String
): Thread {
val thread = Thread(
ThreadInternal(
id.toString(),
name.toString(),
errorType,
isErrorReportingThread,
state,
Stacktrace(ArrayList())
),
logger
)
threads.add(thread)
return thread
}

fun leaveBreadcrumb(
message: String?,
type: BreadcrumbType?,
metadata: MutableMap<String, Any?>?
): Breadcrumb {
val breadcrumb = Breadcrumb(
message.toString(),
type ?: BreadcrumbType.MANUAL,
metadata,
Date(),
logger
)

breadcrumbs.add(breadcrumb)
return breadcrumb
}
}
Loading
Loading