diff --git a/bugsnag-android-core/api/bugsnag-android-core.api b/bugsnag-android-core/api/bugsnag-android-core.api index 3509b235bd..f413bdcdbc 100644 --- a/bugsnag-android-core/api/bugsnag-android-core.api +++ b/bugsnag-android-core/api/bugsnag-android-core.api @@ -347,7 +347,7 @@ public final class com/bugsnag/android/ErrorTypes { public final fun setUnhandledRejections (Z)V } -public class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, com/bugsnag/android/JsonStream$Streamable, com/bugsnag/android/MetadataAware, com/bugsnag/android/UserAware { +public final class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, com/bugsnag/android/JsonStream$Streamable, com/bugsnag/android/MetadataAware, com/bugsnag/android/UserAware { public fun addFeatureFlag (Ljava/lang/String;)V public fun addFeatureFlag (Ljava/lang/String;Ljava/lang/String;)V public fun addFeatureFlags (Ljava/lang/Iterable;)V @@ -357,31 +357,93 @@ public class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, c public fun clearFeatureFlags ()V public fun clearMetadata (Ljava/lang/String;)V public fun clearMetadata (Ljava/lang/String;Ljava/lang/String;)V - public fun getApiKey ()Ljava/lang/String; - public fun getApp ()Lcom/bugsnag/android/AppWithState; - public fun getBreadcrumbs ()Ljava/util/List; - public fun getContext ()Ljava/lang/String; - public fun getDevice ()Lcom/bugsnag/android/DeviceWithState; - public fun getErrors ()Ljava/util/List; - public fun getFeatureFlags ()Ljava/util/List; - public fun getGroupingHash ()Ljava/lang/String; + public final fun getApiKey ()Ljava/lang/String; + public final fun getApp ()Lcom/bugsnag/android/AppWithState; + public final fun getBreadcrumbs ()Ljava/util/List; + public final fun getContext ()Ljava/lang/String; + public final fun getDevice ()Lcom/bugsnag/android/DeviceWithState; + public final fun getErrors ()Ljava/util/List; + public final fun getFeatureFlags ()Ljava/util/List; + public final fun getGroupingHash ()Ljava/lang/String; + public final fun getImpl ()Lcom/bugsnag/android/EventInternal; public fun getMetadata (Ljava/lang/String;)Ljava/util/Map; public fun getMetadata (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; - public fun getOriginalError ()Ljava/lang/Throwable; - public fun getSeverity ()Lcom/bugsnag/android/Severity; - public fun getThreads ()Ljava/util/List; + public final fun getOriginalError ()Ljava/lang/Throwable; + public final fun getSession ()Lcom/bugsnag/android/Session; + public final fun getSeverity ()Lcom/bugsnag/android/Severity; + public final fun getThreads ()Ljava/util/List; public fun getUser ()Lcom/bugsnag/android/User; - public fun isUnhandled ()Z - public fun setApiKey (Ljava/lang/String;)V - public fun setContext (Ljava/lang/String;)V - public fun setGroupingHash (Ljava/lang/String;)V - public fun setSeverity (Lcom/bugsnag/android/Severity;)V - public fun setUnhandled (Z)V + public final fun isUnhandled ()Z + public final fun setApiKey (Ljava/lang/String;)V + public final fun setApp (Lcom/bugsnag/android/AppWithState;)V + public final fun setBreadcrumbs (Ljava/util/List;)V + public final fun setContext (Ljava/lang/String;)V + public final fun setDevice (Lcom/bugsnag/android/DeviceWithState;)V + public final fun setGroupingHash (Ljava/lang/String;)V + public final fun setInternalMetrics (Lcom/bugsnag/android/internal/InternalMetrics;)V + public final fun setRedactedKeys (Ljava/util/Collection;)V + public final fun setSession (Lcom/bugsnag/android/Session;)V + public final fun setSeverity (Lcom/bugsnag/android/Severity;)V + public final fun setUnhandled (Z)V + public fun setUser (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public final fun shouldDiscardClass ()Z + public fun toStream (Lcom/bugsnag/android/JsonStream;)V + public final fun updateSeverityInternal (Lcom/bugsnag/android/Severity;)V + public final fun updateSeverityReason (Ljava/lang/String;)V +} + +public final class com/bugsnag/android/EventInternal : com/bugsnag/android/FeatureFlagAware, com/bugsnag/android/JsonStream$Streamable, com/bugsnag/android/MetadataAware, com/bugsnag/android/UserAware { + public field app Lcom/bugsnag/android/AppWithState; + public field device Lcom/bugsnag/android/DeviceWithState; + public fun (Lcom/bugsnag/android/internal/ImmutableConfig;Lcom/bugsnag/android/SeverityReason;)V + public fun (Ljava/lang/Throwable;Lcom/bugsnag/android/internal/ImmutableConfig;Lcom/bugsnag/android/SeverityReason;)V + public fun (Ljava/lang/Throwable;Lcom/bugsnag/android/internal/ImmutableConfig;Lcom/bugsnag/android/SeverityReason;Lcom/bugsnag/android/Metadata;)V + 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 clearFeatureFlag (Ljava/lang/String;)V + public fun clearFeatureFlags ()V + public fun clearMetadata (Ljava/lang/String;)V + public fun clearMetadata (Ljava/lang/String;Ljava/lang/String;)V + public final fun getApiKey ()Ljava/lang/String; + public final fun getApp ()Lcom/bugsnag/android/AppWithState; + public final fun getBreadcrumbs ()Ljava/util/List; + public final fun getContext ()Ljava/lang/String; + public final fun getDevice ()Lcom/bugsnag/android/DeviceWithState; + public final fun getErrors ()Ljava/util/List; + public final fun getGroupingHash ()Ljava/lang/String; + public final fun getInternalMetrics ()Lcom/bugsnag/android/internal/InternalMetrics; + public final fun getLogger ()Lcom/bugsnag/android/Logger; + public fun getMetadata (Ljava/lang/String;)Ljava/util/Map; + public fun getMetadata (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; + public final fun getOriginalError ()Ljava/lang/Throwable; + public final fun getOriginalUnhandled ()Z + public final fun getRedactedKeys ()Ljava/util/Collection; + public final fun getSeverity ()Lcom/bugsnag/android/Severity; + public final fun getSeverityReasonType ()Ljava/lang/String; + public final fun getThreads ()Ljava/util/List; + public final fun getUnhandled ()Z + public final fun getUnhandledOverridden ()Z + public fun getUser ()Lcom/bugsnag/android/User; + public final fun setApiKey (Ljava/lang/String;)V + public final fun setApp (Lcom/bugsnag/android/AppWithState;)V + public final fun setBreadcrumbs (Ljava/util/List;)V + public final fun setContext (Ljava/lang/String;)V + public final fun setDevice (Lcom/bugsnag/android/DeviceWithState;)V + public final fun setErrors (Ljava/util/List;)V + public final fun setGroupingHash (Ljava/lang/String;)V + public final fun setInternalMetrics (Lcom/bugsnag/android/internal/InternalMetrics;)V + public final fun setRedactedKeys (Ljava/util/Collection;)V + public final fun setSeverity (Lcom/bugsnag/android/Severity;)V + public final fun setThreads (Ljava/util/List;)V + public final fun setUnhandled (Z)V public fun setUser (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - protected fun shouldDiscardClass ()Z + public final fun shouldDiscardClass ()Z public fun toStream (Lcom/bugsnag/android/JsonStream;)V - protected fun updateSeverityInternal (Lcom/bugsnag/android/Severity;)V - protected fun updateSeverityReason (Ljava/lang/String;)V + public final fun updateSeverityInternal (Lcom/bugsnag/android/Severity;)V + public final fun updateSeverityReason (Ljava/lang/String;)V } public final class com/bugsnag/android/EventPayload : com/bugsnag/android/JsonStream$Streamable { diff --git a/bugsnag-android-core/detekt-baseline.xml b/bugsnag-android-core/detekt-baseline.xml index bccf015f28..aa4c31e27f 100644 --- a/bugsnag-android-core/detekt-baseline.xml +++ b/bugsnag-android-core/detekt-baseline.xml @@ -3,6 +3,7 @@ CyclomaticComplexMethod:ConfigInternal.kt$ConfigInternal$fun getConfigDifferences(): Map<String, Any> + EmptySecondaryConstructor:Event.kt$Event${ } ImplicitDefaultLocale:DeliveryHeaders.kt$String.format("%02x", byte) LongParameterList:App.kt$App$( /** * The architecture of the running application binary */ var binaryArch: String?, /** * The package name of the application */ var id: String?, /** * The release stage set in [Configuration.releaseStage] */ var releaseStage: String?, /** * The version of the application set in [Configuration.version] */ var version: String?, /** The revision ID from the manifest (React Native apps only) */ var codeBundleId: String?, /** * The unique identifier for the build of the application set in [Configuration.buildUuid] */ var buildUuid: String?, /** * The application type set in [Configuration#version] */ var type: String?, /** * The version code of the application set in [Configuration.versionCode] */ var versionCode: Number? ) LongParameterList:AppDataCollector.kt$AppDataCollector$( appContext: Context, private val packageManager: PackageManager?, private val config: ImmutableConfig, private val sessionTracker: SessionTracker, private val activityManager: ActivityManager?, private val launchCrashTracker: LaunchCrashTracker, private val memoryTrimState: MemoryTrimState ) @@ -41,9 +42,6 @@ NestedBlockDepth:JsonHelper.kt$JsonHelper$fun jsonToLong(value: Any?): Long? ProtectedMemberInFinalClass:ConfigInternal.kt$ConfigInternal$protected val plugins = HashSet<Plugin>() ProtectedMemberInFinalClass:EventInternal.kt$EventInternal$protected fun isAnr(event: Event): Boolean - ProtectedMemberInFinalClass:EventInternal.kt$EventInternal$protected fun shouldDiscardClass(): Boolean - ProtectedMemberInFinalClass:EventInternal.kt$EventInternal$protected fun updateSeverityInternal(severity: Severity) - ProtectedMemberInFinalClass:EventInternal.kt$EventInternal$protected fun updateSeverityReason(@SeverityReason.SeverityReasonType reason: String) ReturnCount:DefaultDelivery.kt$DefaultDelivery$fun deliver( urlString: String, json: ByteArray, headers: Map<String, String?> ): DeliveryStatus SpreadOperator:FileStore.kt$FileStore$(*listFiles) SwallowedException:AppDataCollector.kt$AppDataCollector$e: Exception @@ -64,7 +62,9 @@ ThrowsCount:JsonHelper.kt$JsonHelper$fun jsonToLong(value: Any?): Long? TooManyFunctions:ConfigInternal.kt$ConfigInternal : CallbackAwareMetadataAwareUserAwareFeatureFlagAware TooManyFunctions:DeviceDataCollector.kt$DeviceDataCollector + TooManyFunctions:Event.kt$Event : StreamableMetadataAwareUserAwareFeatureFlagAware TooManyFunctions:EventInternal.kt$EventInternal : FeatureFlagAwareStreamableMetadataAwareUserAware + UnusedPrivateMember:Event.kt$Event$private fun logNull(property: String) UnusedPrivateProperty:ManifestConfigLoader.kt$ManifestConfigLoader.Companion$private const val LAUNCH_CRASH_THRESHOLD_MS = "$BUGSNAG_NS.LAUNCH_CRASH_THRESHOLD_MS" UnusedPrivateProperty:ThreadStateTest.kt$ThreadStateTest$private val configuration = generateImmutableConfig() UseCheckOrError:BackgroundTaskServiceTest.kt$BackgroundTaskServiceTest$throw IllegalStateException() diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.java index ac498bb174..c4acc61e0c 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.java +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.java @@ -1,429 +1,429 @@ -package com.bugsnag.android; - -import com.bugsnag.android.internal.ImmutableConfig; -import com.bugsnag.android.internal.InternalMetrics; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * An Event object represents a Throwable captured by Bugsnag and is available as a parameter on - * an {@link OnErrorCallback}, where individual properties can be mutated before an error report is - * sent to Bugsnag's API. - */ -@SuppressWarnings("ConstantConditions") -public class Event implements JsonStream.Streamable, MetadataAware, UserAware, FeatureFlagAware { - - private final EventInternal impl; - private final Logger logger; - - Event(@Nullable Throwable originalError, - @NonNull ImmutableConfig config, - @NonNull SeverityReason severityReason, - @NonNull Logger logger) { - this(originalError, config, severityReason, new Metadata(), new FeatureFlags(), logger); - } - - Event(@Nullable Throwable originalError, - @NonNull ImmutableConfig config, - @NonNull SeverityReason severityReason, - @NonNull Metadata metadata, - @NonNull FeatureFlags featureFlags, - @NonNull Logger logger) { - this(new EventInternal(originalError, config, severityReason, metadata, featureFlags), - logger); - } - - Event(@NonNull EventInternal impl, @NonNull Logger logger) { - this.impl = impl; - this.logger = logger; - } - - private void logNull(String property) { - logger.e("Invalid null value supplied to config." + property + ", ignoring"); - } - - /** - * The Throwable object that caused the event in your application. - * - * 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. - */ - @Nullable - public Throwable getOriginalError() { - return impl.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()}. - * - * A reference to the actual {@link Throwable} object that caused the event is available - * through {@link Event#getOriginalError()} ()}. - */ - @NonNull - public List getErrors() { - return impl.getErrors(); - } - - /** - * If thread state is being captured along with the event, this field will contain a - * list of {@link Thread} objects. - */ - @NonNull - public List getThreads() { - return impl.getThreads(); - } - - /** - * 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. - */ - @NonNull - public List getBreadcrumbs() { - return impl.getBreadcrumbs(); - } - - /** - * A list of feature flags active at the time of the event. - * See {@link FeatureFlag} for details of the data available. - */ - @NonNull - public List getFeatureFlags() { - return impl.getFeatureFlags().toList(); - } - - /** - * Information set by the notifier about your app can be found in this field. These values - * can be accessed and amended if necessary. - */ - @NonNull - public AppWithState getApp() { - return impl.getApp(); - } - - /** - * Information set by the notifier about your device can be found in this field. These values - * can be accessed and amended if necessary. - */ - @NonNull - public DeviceWithState getDevice() { - return impl.getDevice(); - } - - /** - * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag - * is initialized, you may choose to send certain events to a different Bugsnag project. - */ - public void setApiKey(@NonNull String apiKey) { - if (apiKey != null) { - impl.setApiKey(apiKey); - } else { - logNull("apiKey"); - } - } - - /** - * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag - * is initialized, you may choose to send certain events to a different Bugsnag project. - */ - @NonNull - public String getApiKey() { - return impl.getApiKey(); - } - - /** - * The severity of the event. By default, unhandled exceptions will be {@link Severity#ERROR} - * and handled exceptions sent with {@link Bugsnag#notify} {@link Severity#WARNING}. - */ - public void setSeverity(@NonNull Severity severity) { - if (severity != null) { - impl.setSeverity(severity); - } else { - logNull("severity"); - } - } - - /** - * The severity of the event. By default, unhandled exceptions will be {@link Severity#ERROR} - * and handled exceptions sent with {@link Bugsnag#notify} {@link Severity#WARNING}. - */ - @NonNull - public Severity getSeverity() { - return impl.getSeverity(); - } - - /** - * Set the grouping hash of the event to override the default grouping on the dashboard. - * 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. - * - * As the name implies, this option accepts a hash of sorts. - */ - public void setGroupingHash(@Nullable String groupingHash) { - impl.setGroupingHash(groupingHash); - } - - /** - * Set the grouping hash of the event to override the default grouping on the dashboard. - * 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. - * - * As the name implies, this option accepts a hash of sorts. - */ - @Nullable - public String getGroupingHash() { - return impl.getGroupingHash(); - } - - /** - * Sets the context of the error. The context is a summary what what was occurring in the - * application at the time of the crash, if available, such as the visible activity. - */ - public void setContext(@Nullable String context) { - impl.setContext(context); - } - - /** - * Returns the context of the error. The context is a summary what what was occurring in the - * application at the time of the crash, if available, such as the visible activity. - */ - @Nullable - public String getContext() { - return impl.getContext(); - } - - /** - * Sets the user associated with the event. - */ - @Override - public void setUser(@Nullable String id, @Nullable String email, @Nullable String name) { - impl.setUser(id, email, name); - } - - /** - * Returns the currently set User information. - */ - @Override - @NonNull - public User getUser() { - return impl.getUser(); - } - - /** - * Adds a map of multiple metadata key-value pairs to the specified section. - */ - @Override - public void addMetadata(@NonNull String section, @NonNull Map value) { - if (section != null && value != null) { - impl.addMetadata(section, value); - } else { - logNull("addMetadata"); - } - } - - /** - * Adds the specified key and value in the specified section. The value can be of - * any primitive type or a collection such as a map, set or array. - */ - @Override - public void addMetadata(@NonNull String section, @NonNull String key, @Nullable Object value) { - if (section != null && key != null) { - impl.addMetadata(section, key, value); - } else { - logNull("addMetadata"); - } - } - - /** - * Removes all the data from the specified section. - */ - @Override - public void clearMetadata(@NonNull String section) { - if (section != null) { - impl.clearMetadata(section); - } else { - logNull("clearMetadata"); - } - } - - /** - * Removes data with the specified key from the specified section. - */ - @Override - public void clearMetadata(@NonNull String section, @NonNull String key) { - if (section != null && key != null) { - impl.clearMetadata(section, key); - } else { - logNull("clearMetadata"); - } - } - - /** - * Returns a map of data in the specified section. - */ - @Override - @Nullable - public Map getMetadata(@NonNull String section) { - if (section != null) { - return impl.getMetadata(section); - } else { - logNull("getMetadata"); - return null; - } - } - - /** - * Returns the value of the specified key in the specified section. - */ - @Override - @Nullable - public Object getMetadata(@NonNull String section, @NonNull String key) { - if (section != null && key != null) { - return impl.getMetadata(section, key); - } else { - logNull("getMetadata"); - return null; - } - } - - /** - * {@inheritDoc} - */ - @Override - public void addFeatureFlag(@NonNull String name) { - if (name != null) { - impl.addFeatureFlag(name); - } else { - logNull("addFeatureFlag"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void addFeatureFlag(@NonNull String name, @Nullable String variant) { - if (name != null) { - impl.addFeatureFlag(name, variant); - } else { - logNull("addFeatureFlag"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void addFeatureFlags(@NonNull Iterable featureFlags) { - if (featureFlags != null) { - impl.addFeatureFlags(featureFlags); - } else { - logNull("addFeatureFlags"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void clearFeatureFlag(@NonNull String name) { - if (name != null) { - impl.clearFeatureFlag(name); - } else { - logNull("clearFeatureFlag"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void clearFeatureFlags() { - impl.clearFeatureFlags(); - } - - @Override - public void toStream(@NonNull JsonStream stream) throws IOException { - impl.toStream(stream); - } - - /** - * Whether the event was a crash (i.e. unhandled) or handled error in which the system - * continued running. - * - * Unhandled errors count towards your stability score. If you don't want certain errors - * to count towards your stability score, you can alter this property through an - * {@link OnErrorCallback}. - */ - public boolean isUnhandled() { - return impl.getUnhandled(); - } - - /** - * Whether the event was a crash (i.e. unhandled) or handled error in which the system - * continued running. - * - * Unhandled errors count towards your stability score. If you don't want certain errors - * to count towards your stability score, you can alter this property through an - * {@link OnErrorCallback}. - */ - public void setUnhandled(boolean unhandled) { - impl.setUnhandled(unhandled); - } - - protected boolean shouldDiscardClass() { - return impl.shouldDiscardClass(); - } - - protected void updateSeverityInternal(@NonNull Severity severity) { - impl.updateSeverityInternal(severity); - } - - protected void updateSeverityReason(@NonNull @SeverityReason.SeverityReasonType String reason) { - impl.updateSeverityReason(reason); - } - - void setApp(@NonNull AppWithState app) { - impl.setApp(app); - } - - void setDevice(@NonNull DeviceWithState device) { - impl.setDevice(device); - } - - void setBreadcrumbs(@NonNull List breadcrumbs) { - impl.setBreadcrumbs(breadcrumbs); - } - - @Nullable - Session getSession() { - return impl.session; - } - - void setSession(@Nullable Session session) { - impl.session = session; - } - - EventInternal getImpl() { - return impl; - } - - void setRedactedKeys(Collection redactedKeys) { - impl.setRedactedKeys(redactedKeys); - } - - void setInternalMetrics(InternalMetrics metrics) { - impl.setInternalMetrics(metrics); - } -} +//package com.bugsnag.android; +// +//import com.bugsnag.android.internal.ImmutableConfig; +//import com.bugsnag.android.internal.InternalMetrics; +// +//import androidx.annotation.NonNull; +//import androidx.annotation.Nullable; +// +//import java.io.IOException; +//import java.util.Collection; +//import java.util.List; +//import java.util.Map; +//import java.util.regex.Pattern; +// +///** +// * An Event object represents a Throwable captured by Bugsnag and is available as a parameter on +// * an {@link OnErrorCallback}, where individual properties can be mutated before an error report is +// * sent to Bugsnag's API. +// */ +//@SuppressWarnings("ConstantConditions") +//public class Event implements JsonStream.Streamable, MetadataAware, UserAware, FeatureFlagAware { +// +// private final EventInternal impl; +// private final Logger logger; +// +// Event(@Nullable Throwable originalError, +// @NonNull ImmutableConfig config, +// @NonNull SeverityReason severityReason, +// @NonNull Logger logger) { +// this(originalError, config, severityReason, new Metadata(), new FeatureFlags(), logger); +// } +// +// Event(@Nullable Throwable originalError, +// @NonNull ImmutableConfig config, +// @NonNull SeverityReason severityReason, +// @NonNull Metadata metadata, +// @NonNull FeatureFlags featureFlags, +// @NonNull Logger logger) { +// this(new EventInternal(originalError, config, severityReason, metadata, featureFlags), +// logger); +// } +// +// Event(@NonNull EventInternal impl, @NonNull Logger logger) { +// this.impl = impl; +// this.logger = logger; +// } +// +// private void logNull(String property) { +// logger.e("Invalid null value supplied to config." + property + ", ignoring"); +// } +// +// /** +// * The Throwable object that caused the event in your application. +// * +// * 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. +// */ +// @Nullable +// public Throwable getOriginalError() { +// return impl.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()}. +// * +// * A reference to the actual {@link Throwable} object that caused the event is available +// * through {@link Event#getOriginalError()} ()}. +// */ +// @NonNull +// public List getErrors() { +// return impl.getErrors(); +// } +// +// /** +// * If thread state is being captured along with the event, this field will contain a +// * list of {@link Thread} objects. +// */ +// @NonNull +// public List getThreads() { +// return impl.getThreads(); +// } +// +// /** +// * 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. +// */ +// @NonNull +// public List getBreadcrumbs() { +// return impl.getBreadcrumbs(); +// } +// +// /** +// * A list of feature flags active at the time of the event. +// * See {@link FeatureFlag} for details of the data available. +// */ +// @NonNull +// public List getFeatureFlags() { +// return impl.getFeatureFlags().toList(); +// } +// +// /** +// * Information set by the notifier about your app can be found in this field. These values +// * can be accessed and amended if necessary. +// */ +// @NonNull +// public AppWithState getApp() { +// return impl.getApp(); +// } +// +// /** +// * Information set by the notifier about your device can be found in this field. These values +// * can be accessed and amended if necessary. +// */ +// @NonNull +// public DeviceWithState getDevice() { +// return impl.getDevice(); +// } +// +// /** +// * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag +// * is initialized, you may choose to send certain events to a different Bugsnag project. +// */ +// public void setApiKey(@NonNull String apiKey) { +// if (apiKey != null) { +// impl.setApiKey(apiKey); +// } else { +// logNull("apiKey"); +// } +// } +// +// /** +// * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag +// * is initialized, you may choose to send certain events to a different Bugsnag project. +// */ +// @NonNull +// public String getApiKey() { +// return impl.getApiKey(); +// } +// +// /** +// * The severity of the event. By default, unhandled exceptions will be {@link Severity#ERROR} +// * and handled exceptions sent with {@link Bugsnag#notify} {@link Severity#WARNING}. +// */ +// public void setSeverity(@NonNull Severity severity) { +// if (severity != null) { +// impl.setSeverity(severity); +// } else { +// logNull("severity"); +// } +// } +// +// /** +// * The severity of the event. By default, unhandled exceptions will be {@link Severity#ERROR} +// * and handled exceptions sent with {@link Bugsnag#notify} {@link Severity#WARNING}. +// */ +// @NonNull +// public Severity getSeverity() { +// return impl.getSeverity(); +// } +// +// /** +// * Set the grouping hash of the event to override the default grouping on the dashboard. +// * 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. +// * +// * As the name implies, this option accepts a hash of sorts. +// */ +// public void setGroupingHash(@Nullable String groupingHash) { +// impl.setGroupingHash(groupingHash); +// } +// +// /** +// * Set the grouping hash of the event to override the default grouping on the dashboard. +// * 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. +// * +// * As the name implies, this option accepts a hash of sorts. +// */ +// @Nullable +// public String getGroupingHash() { +// return impl.getGroupingHash(); +// } +// +// /** +// * Sets the context of the error. The context is a summary what what was occurring in the +// * application at the time of the crash, if available, such as the visible activity. +// */ +// public void setContext(@Nullable String context) { +// impl.setContext(context); +// } +// +// /** +// * Returns the context of the error. The context is a summary what what was occurring in the +// * application at the time of the crash, if available, such as the visible activity. +// */ +// @Nullable +// public String getContext() { +// return impl.getContext(); +// } +// +// /** +// * Sets the user associated with the event. +// */ +// @Override +// public void setUser(@Nullable String id, @Nullable String email, @Nullable String name) { +// impl.setUser(id, email, name); +// } +// +// /** +// * Returns the currently set User information. +// */ +// @Override +// @NonNull +// public User getUser() { +// return impl.getUser(); +// } +// +// /** +// * Adds a map of multiple metadata key-value pairs to the specified section. +// */ +// @Override +// public void addMetadata(@NonNull String section, @NonNull Map value) { +// if (section != null && value != null) { +// impl.addMetadata(section, value); +// } else { +// logNull("addMetadata"); +// } +// } +// +// /** +// * Adds the specified key and value in the specified section. The value can be of +// * any primitive type or a collection such as a map, set or array. +// */ +// @Override +// public void addMetadata(@NonNull String section, @NonNull String key, @Nullable Object value) { +// if (section != null && key != null) { +// impl.addMetadata(section, key, value); +// } else { +// logNull("addMetadata"); +// } +// } +// +// /** +// * Removes all the data from the specified section. +// */ +// @Override +// public void clearMetadata(@NonNull String section) { +// if (section != null) { +// impl.clearMetadata(section); +// } else { +// logNull("clearMetadata"); +// } +// } +// +// /** +// * Removes data with the specified key from the specified section. +// */ +// @Override +// public void clearMetadata(@NonNull String section, @NonNull String key) { +// if (section != null && key != null) { +// impl.clearMetadata(section, key); +// } else { +// logNull("clearMetadata"); +// } +// } +// +// /** +// * Returns a map of data in the specified section. +// */ +// @Override +// @Nullable +// public Map getMetadata(@NonNull String section) { +// if (section != null) { +// return impl.getMetadata(section); +// } else { +// logNull("getMetadata"); +// return null; +// } +// } +// +// /** +// * Returns the value of the specified key in the specified section. +// */ +// @Override +// @Nullable +// public Object getMetadata(@NonNull String section, @NonNull String key) { +// if (section != null && key != null) { +// return impl.getMetadata(section, key); +// } else { +// logNull("getMetadata"); +// return null; +// } +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public void addFeatureFlag(@NonNull String name) { +// if (name != null) { +// impl.addFeatureFlag(name); +// } else { +// logNull("addFeatureFlag"); +// } +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public void addFeatureFlag(@NonNull String name, @Nullable String variant) { +// if (name != null) { +// impl.addFeatureFlag(name, variant); +// } else { +// logNull("addFeatureFlag"); +// } +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public void addFeatureFlags(@NonNull Iterable featureFlags) { +// if (featureFlags != null) { +// impl.addFeatureFlags(featureFlags); +// } else { +// logNull("addFeatureFlags"); +// } +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public void clearFeatureFlag(@NonNull String name) { +// if (name != null) { +// impl.clearFeatureFlag(name); +// } else { +// logNull("clearFeatureFlag"); +// } +// } +// +// /** +// * {@inheritDoc} +// */ +// @Override +// public void clearFeatureFlags() { +// impl.clearFeatureFlags(); +// } +// +// @Override +// public void toStream(@NonNull JsonStream stream) throws IOException { +// impl.toStream(stream); +// } +// +// /** +// * Whether the event was a crash (i.e. unhandled) or handled error in which the system +// * continued running. +// * +// * Unhandled errors count towards your stability score. If you don't want certain errors +// * to count towards your stability score, you can alter this property through an +// * {@link OnErrorCallback}. +// */ +// public boolean isUnhandled() { +// return impl.getUnhandled(); +// } +// +// /** +// * Whether the event was a crash (i.e. unhandled) or handled error in which the system +// * continued running. +// * +// * Unhandled errors count towards your stability score. If you don't want certain errors +// * to count towards your stability score, you can alter this property through an +// * {@link OnErrorCallback}. +// */ +// public void setUnhandled(boolean unhandled) { +// impl.setUnhandled(unhandled); +// } +// +// protected boolean shouldDiscardClass() { +// return impl.shouldDiscardClass(); +// } +// +// protected void updateSeverityInternal(@NonNull Severity severity) { +// impl.updateSeverityInternal(severity); +// } +// +// protected void updateSeverityReason(@NonNull @SeverityReason.SeverityReasonType String reason) { +// impl.updateSeverityReason(reason); +// } +// +// void setApp(@NonNull AppWithState app) { +// impl.setApp(app); +// } +// +// void setDevice(@NonNull DeviceWithState device) { +// impl.setDevice(device); +// } +// +// void setBreadcrumbs(@NonNull List breadcrumbs) { +// impl.setBreadcrumbs(breadcrumbs); +// } +// +// @Nullable +// Session getSession() { +// return impl.session; +// } +// +// void setSession(@Nullable Session session) { +// impl.session = session; +// } +// +// EventInternal getImpl() { +// return impl; +// } +// +// void setRedactedKeys(Collection redactedKeys) { +// impl.setRedactedKeys(redactedKeys); +// } +// +// void setInternalMetrics(InternalMetrics metrics) { +// impl.setInternalMetrics(metrics); +// } +//} diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.kt new file mode 100644 index 0000000000..f94614d274 --- /dev/null +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.kt @@ -0,0 +1,302 @@ +package com.bugsnag.android + +import com.bugsnag.android.JsonStream.Streamable +import com.bugsnag.android.SeverityReason.SeverityReasonType +import com.bugsnag.android.internal.ImmutableConfig +import com.bugsnag.android.internal.InternalMetrics +import java.io.IOException +import java.util.regex.Pattern + +/** + * An Event object represents a Throwable captured by Bugsnag and is available as a parameter on + * an [OnErrorCallback], where individual properties can be mutated before an error report is + * sent to Bugsnag's API. + */ +class Event internal constructor( + internal val impl: EventInternal, + private val logger: Logger +) : Streamable, MetadataAware, UserAware, FeatureFlagAware { + internal constructor( + originalError: Throwable?, + config: ImmutableConfig, + severityReason: SeverityReason, + logger: Logger + ) : this(originalError, config, severityReason, Metadata(), FeatureFlags(), logger) { + } + + internal constructor( + originalError: Throwable?, + config: ImmutableConfig, + severityReason: SeverityReason, + metadata: Metadata, + featureFlags: FeatureFlags, + logger: Logger + ) : this( + EventInternal(originalError, config, severityReason, metadata, featureFlags), + logger + ) { + } + + private fun logNull(property: String) { + logger.e("Invalid null value supplied to config.$property, ignoring") + } + + /** + * The Throwable object that caused the event in your application. + * + * Manipulating this field does not affect the error information reported to the + * Bugsnag dashboard. Use [Event.getErrors] to access and amend the representation of + * the error that will be sent. + */ + val originalError: Throwable? + get() = impl.originalError + + /** + * Information extracted from the [Throwable] that caused the event can be found in this + * field. The list contains at least one [Error] that represents the thrown object + * with subsequent elements in the list populated from [Throwable.getCause]. + * + * A reference to the actual [Throwable] object that caused the event is available + * through [Event.getOriginalError] ()}. + */ + val errors: MutableList + get() = impl.errors + + /** + * If thread state is being captured along with the event, this field will contain a + * list of [Thread] objects. + */ + val threads: MutableList + get() = impl.threads + + /** + * A list of breadcrumbs leading up to the event. These values can be accessed and amended + * if necessary. See [Breadcrumb] for details of the data available. + */ + var breadcrumbs: MutableList + get() = impl.breadcrumbs + set(breadcrumbs) { + impl.breadcrumbs = breadcrumbs.toMutableList() + } + + /** + * A list of feature flags active at the time of the event. + * See [FeatureFlag] for details of the data available. + */ + val featureFlags: List + get() = impl.featureFlags.toList() + + /** + * Information set by the notifier about your app can be found in this field. These values + * can be accessed and amended if necessary. + */ + var app: AppWithState + get() = impl.app + set(app) { + impl.app = app + } + + /** + * Information set by the notifier about your device can be found in this field. These values + * can be accessed and amended if necessary. + */ + var device: DeviceWithState + get() = impl.device + set(device) { + impl.device = device + } + /** + * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag + * is initialized, you may choose to send certain events to a different Bugsnag project. + */ + /** + * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag + * is initialized, you may choose to send certain events to a different Bugsnag project. + */ + var apiKey: String + get() = impl.apiKey + set(apiKey) { + impl.apiKey = apiKey + } + /** + * The severity of the event. By default, unhandled exceptions will be [Severity.ERROR] + * and handled exceptions sent with [Bugsnag.notify] [Severity.WARNING]. + */ + /** + * The severity of the event. By default, unhandled exceptions will be [Severity.ERROR] + * and handled exceptions sent with [Bugsnag.notify] [Severity.WARNING]. + */ + var severity: Severity + get() = impl.severity + set(severity) { + impl.severity = severity + } + /** + * Set the grouping hash of the event to override the default grouping on the dashboard. + * 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. + * + * As the name implies, this option accepts a hash of sorts. + */ + /** + * Set the grouping hash of the event to override the default grouping on the dashboard. + * 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. + * + * As the name implies, this option accepts a hash of sorts. + */ + var groupingHash: String? + get() = impl.groupingHash + set(groupingHash) { + impl.groupingHash = groupingHash + } + /** + * Returns the context of the error. The context is a summary what what was occurring in the + * application at the time of the crash, if available, such as the visible activity. + */ + /** + * Sets the context of the error. The context is a summary what what was occurring in the + * application at the time of the crash, if available, such as the visible activity. + */ + var context: String? + get() = impl.context + set(context) { + impl.context = context + } + + /** + * Sets the user associated with the event. + */ + override fun setUser(id: String?, email: String?, name: String?) { + impl.setUser(id, email, name) + } + + /** + * Returns the currently set User information. + */ + override fun getUser(): User { + return impl.getUser() + } + + /** + * Adds a map of multiple metadata key-value pairs to the specified section. + */ + override fun addMetadata(section: String, value: Map) { + impl.addMetadata(section, value) + } + + /** + * Adds the specified key and value in the specified section. The value can be of + * any primitive type or a collection such as a map, set or array. + */ + override fun addMetadata(section: String, key: String, value: Any?) { + impl.addMetadata(section, key, value) + } + + /** + * Removes all the data from the specified section. + */ + override fun clearMetadata(section: String) { + impl.clearMetadata(section) + } + + /** + * Removes data with the specified key from the specified section. + */ + override fun clearMetadata(section: String, key: String) { + impl.clearMetadata(section, key) + } + + /** + * Returns a map of data in the specified section. + */ + override fun getMetadata(section: String): Map? { + return impl.getMetadata(section) + } + + /** + * Returns the value of the specified key in the specified section. + */ + override fun getMetadata(section: String, key: String): Any? { + return impl.getMetadata(section, key) + } + + /** + * {@inheritDoc} + */ + override fun addFeatureFlag(name: String) { + impl.addFeatureFlag(name) + } + + /** + * {@inheritDoc} + */ + override fun addFeatureFlag(name: String, variant: String?) { + impl.addFeatureFlag(name, variant) + } + + /** + * {@inheritDoc} + */ + override fun addFeatureFlags(featureFlags: Iterable) { + impl.addFeatureFlags(featureFlags) + } + + /** + * {@inheritDoc} + */ + override fun clearFeatureFlag(name: String) { + impl.clearFeatureFlag(name) + } + + /** + * {@inheritDoc} + */ + override fun clearFeatureFlags() { + impl.clearFeatureFlags() + } + + @Throws(IOException::class) + override fun toStream(stream: JsonStream) { + impl.toStream(stream) + } + + fun isUnhandled(): Boolean { + return impl.unhandled + } + + fun setUnhandled(value: Boolean) { + impl.unhandled = value + } + + fun shouldDiscardClass(): Boolean { + return impl.shouldDiscardClass() + } + + fun updateSeverityInternal(severity: Severity) { + impl.updateSeverityInternal(severity) + } + + fun updateSeverityReason(@SeverityReasonType reason: String) { + impl.updateSeverityReason(reason) + } + + var session: Session? + get() = impl.session + set(session) { + impl.session = session + } + + fun setRedactedKeys(redactedKeys: Collection) { + impl.redactedKeys = redactedKeys + } + + fun setInternalMetrics(metrics: InternalMetrics?) { + impl.internalMetrics = metrics!! + } + fun getImpl(): EventInternal { + return impl + } +} diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventInternal.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventInternal.kt index 4a1881f71d..0ceac817cc 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventInternal.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventInternal.kt @@ -8,7 +8,7 @@ import com.bugsnag.android.internal.TrimMetrics import java.io.IOException import java.util.regex.Pattern -internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, MetadataAware, UserAware { +class EventInternal : FeatureFlagAware, JsonStream.Streamable, MetadataAware, UserAware { @JvmOverloads internal constructor( @@ -73,8 +73,8 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata internal var severityReason: SeverityReason val logger: Logger - val metadata: Metadata - val featureFlags: FeatureFlags + internal val metadata: Metadata + internal val featureFlags: FeatureFlags private val discardClasses: Set internal var projectPackages: Collection @@ -123,7 +123,7 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata fun getOriginalUnhandled(): Boolean = severityReason.originalUnhandled - protected fun shouldDiscardClass(): Boolean { + public fun shouldDiscardClass(): Boolean { return when { errors.isEmpty() -> true else -> errors.any { error -> @@ -228,7 +228,7 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata this.severityReason = severityReason } - protected fun updateSeverityInternal(severity: Severity) { + public fun updateSeverityInternal(severity: Severity) { severityReason = SeverityReason( severityReason.severityReasonType, severity, @@ -239,7 +239,7 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata ) } - protected fun updateSeverityReason(@SeverityReason.SeverityReasonType reason: String) { + public fun updateSeverityReason(@SeverityReason.SeverityReasonType reason: String) { severityReason = SeverityReason( reason, severityReason.currentSeverity, @@ -252,7 +252,7 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata fun getSeverityReasonType(): String = severityReason.severityReasonType - fun trimMetadataStringsTo(maxLength: Int): TrimMetrics { + internal fun trimMetadataStringsTo(maxLength: Int): TrimMetrics { var stringCount = 0 var charCount = 0 @@ -267,7 +267,7 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata return TrimMetrics(stringCount, charCount) } - fun trimBreadcrumbsBy(byteCount: Int): TrimMetrics { + internal fun trimBreadcrumbsBy(byteCount: Int): TrimMetrics { var removedBreadcrumbCount = 0 var removedByteCount = 0 while (removedByteCount < byteCount && breadcrumbs.isNotEmpty()) { diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventRedactionTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventRedactionTest.kt index 24c41ccf75..97771b7569 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventRedactionTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventRedactionTest.kt @@ -43,7 +43,7 @@ internal class EventRedactionTest { event.addMetadata("device", "password", "bar") event.impl.metadata.addMetadata("baz", "password", "hunter2") val metadata = mutableMapOf(Pair("changeme", "whoops")) - event.breadcrumbs = listOf(Breadcrumb("Whoops", BreadcrumbType.LOG, metadata, Date(0), NoopLogger)) + event.breadcrumbs = mutableListOf(Breadcrumb("Whoops", BreadcrumbType.LOG, metadata, Date(0), NoopLogger)) event.threads.clear() event.device.cpuAbi = emptyArray() diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventSerializationTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventSerializationTest.kt index f930fe313c..50e0665233 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventSerializationTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventSerializationTest.kt @@ -69,7 +69,7 @@ internal class EventSerializationTest { Date(0), NoopLogger ) - it.breadcrumbs = listOf(crumb) + it.breadcrumbs = mutableListOf(crumb) val stacktrace = Stacktrace(arrayOf(), emptySet(), NoopLogger) val err = diff --git a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/EventDeserializerTest.kt b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/EventDeserializerTest.kt index ee5d83e999..0f87884954 100644 --- a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/EventDeserializerTest.kt +++ b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/EventDeserializerTest.kt @@ -79,7 +79,7 @@ class EventDeserializerTest { val event = EventDeserializer(client, emptyList()).deserialize(map) assertNotNull(event) assertEquals(Severity.INFO, event.severity) - assertFalse(event.isUnhandled) + assertFalse(event.isUnhandled()) assertFalse(TestHooks.getUnhandledOverridden(event)) assertEquals("Foo", event.context) assertEquals("SomeHash", event.groupingHash) @@ -113,7 +113,7 @@ class EventDeserializerTest { mapOf(Pair("id", "device-id"), Pair("runtimeVersions", mutableMapOf())) val event = EventDeserializer(client, emptyList()).deserialize(map) - assertFalse(event.isUnhandled) + assertFalse(event.isUnhandled()) assertTrue(TestHooks.getUnhandledOverridden(event)) }