From 4c6b4e867eb7a4099a75ff2c175c4796c12d362a Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 25 Nov 2025 16:22:07 +0000 Subject: [PATCH] feat(http): added Request/Response as optional properties on an Event --- .../api/bugsnag-android-core.api | 36 +++ .../java/com/bugsnag/android/RequestTest.kt | 130 +++++++++++ .../bugsnag/android/AbstractHttpEntity.java | 111 ++++++++++ .../main/java/com/bugsnag/android/Event.java | 154 +++++++++---- .../java/com/bugsnag/android/EventInternal.kt | 7 + .../java/com/bugsnag/android/Request.java | 205 ++++++++++++++++++ .../java/com/bugsnag/android/Response.java | 42 ++++ .../com/bugsnag/android/SeverityReason.java | 4 +- 8 files changed, 644 insertions(+), 45 deletions(-) create mode 100644 bugsnag-android-core/src/androidTest/java/com/bugsnag/android/RequestTest.kt create mode 100644 bugsnag-android-core/src/main/java/com/bugsnag/android/AbstractHttpEntity.java create mode 100644 bugsnag-android-core/src/main/java/com/bugsnag/android/Request.java create mode 100644 bugsnag-android-core/src/main/java/com/bugsnag/android/Response.java diff --git a/bugsnag-android-core/api/bugsnag-android-core.api b/bugsnag-android-core/api/bugsnag-android-core.api index 692f6d1675..91856f93ea 100644 --- a/bugsnag-android-core/api/bugsnag-android-core.api +++ b/bugsnag-android-core/api/bugsnag-android-core.api @@ -1,3 +1,15 @@ +public abstract class com/bugsnag/android/AbstractHttpEntity { + protected final field headers Ljava/util/Map; + public fun addHeader (Ljava/lang/String;Ljava/lang/String;)V + public fun getBody ()Ljava/lang/String; + public fun getBodyLength ()J + public fun getHeader (Ljava/lang/String;)Ljava/lang/String; + public fun getHeaderNames ()Ljava/util/Set; + public fun removeHeader (Ljava/lang/String;)V + public fun setBody (Ljava/lang/String;)V + public fun setBodyLength (J)V +} + public class com/bugsnag/android/App : com/bugsnag/android/JsonStream$Streamable { public final fun getBinaryArch ()Ljava/lang/String; public final fun getBuildUuid ()Ljava/lang/String; @@ -411,6 +423,8 @@ public class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, c 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 getRequest ()Lcom/bugsnag/android/Request; + public fun getResponse ()Lcom/bugsnag/android/Response; public fun getSeverity ()Lcom/bugsnag/android/Severity; public fun getThreads ()Ljava/util/List; public fun getUser ()Lcom/bugsnag/android/User; @@ -424,6 +438,8 @@ public class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, c public fun setErrorReportingThread (Lcom/bugsnag/android/Thread;)V public fun setGroupingDiscriminator (Ljava/lang/String;)Ljava/lang/String; public fun setGroupingHash (Ljava/lang/String;)V + public fun setRequest (Lcom/bugsnag/android/Request;)V + public fun setResponse (Lcom/bugsnag/android/Response;)V public fun setSeverity (Lcom/bugsnag/android/Severity;)V public fun setTraceCorrelation (Ljava/util/UUID;J)V public fun setUnhandled (Z)V @@ -641,6 +657,26 @@ public abstract interface class com/bugsnag/android/Plugin { public abstract fun unload ()V } +public final class com/bugsnag/android/Request : com/bugsnag/android/AbstractHttpEntity, com/bugsnag/android/JsonStream$Streamable { + public fun addQueryParameter (Ljava/lang/String;Ljava/lang/String;)V + public fun getHttpMethod ()Ljava/lang/String; + public fun getHttpVersion ()Ljava/lang/String; + public fun getQueryParameter (Ljava/lang/String;)Ljava/lang/String; + public fun getQueryParameterNames ()Ljava/util/Set; + public fun getUrl ()Ljava/lang/String; + public fun removeQueryParameter (Ljava/lang/String;)V + public fun setHttpMethod (Ljava/lang/String;)V + public fun setHttpVersion (Ljava/lang/String;)V + public fun setUrl (Ljava/lang/String;)V + public fun toStream (Lcom/bugsnag/android/JsonStream;)V +} + +public final class com/bugsnag/android/Response : com/bugsnag/android/AbstractHttpEntity, com/bugsnag/android/JsonStream$Streamable { + public fun getStatusCode ()I + public fun setStatusCode (I)V + public fun toStream (Lcom/bugsnag/android/JsonStream;)V +} + public final class com/bugsnag/android/Session : com/bugsnag/android/Deliverable, com/bugsnag/android/JsonStream$Streamable, com/bugsnag/android/UserAware { public fun getApiKey ()Ljava/lang/String; public fun getApp ()Lcom/bugsnag/android/App; diff --git a/bugsnag-android-core/src/androidTest/java/com/bugsnag/android/RequestTest.kt b/bugsnag-android-core/src/androidTest/java/com/bugsnag/android/RequestTest.kt new file mode 100644 index 0000000000..4657908ef6 --- /dev/null +++ b/bugsnag-android-core/src/androidTest/java/com/bugsnag/android/RequestTest.kt @@ -0,0 +1,130 @@ +package com.bugsnag.android + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class RequestTest { + private val testBodyString = "this is a body string with some content" + private val customBodyLength = 5000L + + private val logger = NoopLogger + + @Test + fun urlQueryIsExtracted() { + val request = Request( + logger, + "GET", + "1.1", + "http://localhost/test?t1=arg1&test2=argument+2" + ) + + assertEquals("http://localhost/test", request.url) + assertEquals("arg1", request.getQueryParameter("t1")) + assertEquals("argument 2", request.getQueryParameter("test2")) + assertEquals(setOf("t1", "test2"), request.queryParameterNames) + } + + @Test + fun setBody() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + request.body = testBodyString + assertEquals(testBodyString, request.body) + } + + @Test + fun setBodyWithUserLength() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + request.bodyLength = customBodyLength + request.body = testBodyString + + assertEquals(testBodyString, request.body) + assertEquals(customBodyLength, request.bodyLength) + } + + @Test + fun setNullBody() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + request.body = testBodyString + request.body = null + assertNull(request.body) + } + + @Test + fun setHttpMethod() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + assertEquals("GET", request.httpMethod) + + request.httpMethod = "POST" + assertEquals("POST", request.httpMethod) + } + + @Test + fun setHttpVersion() { + val request = Request(logger, "1.1", "1.1", "http://localhost/") + assertEquals("1.1", request.httpVersion) + + request.httpVersion = "1.0" + assertEquals("1.0", request.httpVersion) + } + + @Test + fun setUrl() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + assertEquals("http://localhost/", request.url) + + request.url = "https://google.com" + assertEquals("https://google.com", request.url) + } + + @Test + fun setUrlWithQuery() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + request.url = "http://foo.com?a=1&b=2" + assertEquals("http://foo.com", request.url) + assertEquals("1", request.getQueryParameter("a")) + assertEquals("2", request.getQueryParameter("b")) + assertEquals(setOf("a", "b"), request.queryParameterNames) + } + + @Test + fun queryParameters() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + request.addQueryParameter("foo", "bar") + request.addQueryParameter("another", "param") + + assertEquals("bar", request.getQueryParameter("foo")) + assertEquals("param", request.getQueryParameter("another")) + assertEquals(setOf("foo", "another"), request.queryParameterNames) + + request.removeQueryParameter("foo") + assertNull(request.getQueryParameter("foo")) + assertEquals(setOf("another"), request.queryParameterNames) + } + + @Test + fun headers() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + request.addHeader("X-Test", "value") + request.addHeader("Another-Header", "another-value") + + assertEquals("X-Test", request.getHeader("X-Test")) + assertEquals("Another-Header", request.getHeader("Another-Header")) + assertEquals(setOf("X-Test", "Another-Header"), request.headerNames) + + request.removeHeader("X-Test") + assertEquals("", request.getHeader("X-Test")) + assertEquals(setOf("Another-Header"), request.headerNames) + } + + @Test + fun setBodyLength() { + val request = Request(logger, "GET", "1.1", "http://localhost/") + request.bodyLength = 1234 + assertEquals(1234, request.bodyLength) + + // test negative value is ignored + request.bodyLength = -5 + assertEquals(1234, request.bodyLength) + } +} diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/AbstractHttpEntity.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/AbstractHttpEntity.java new file mode 100644 index 0000000000..79bd16790e --- /dev/null +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/AbstractHttpEntity.java @@ -0,0 +1,111 @@ +package com.bugsnag.android; + +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +@SuppressWarnings("ConstantValue") +public abstract class AbstractHttpEntity { + protected final Map headers = new LinkedHashMap<>(); + + @Nullable + private String body; + private long bodyLength = -1L; + + // package-protected constructor + AbstractHttpEntity() { + } + + /** + * Add a header to this reported HTTP entity. + * + * @param name the name of the header + * @param value the value of the header + */ + public void addHeader(@NonNull String name, @NonNull String value) { + if (name == null || value == null) { + return; + } + + headers.put(name, value); + } + + /** + * Remove the specified header by name (case-sensitive). + * + * @param name the header to remove + */ + public void removeHeader(@NonNull String name) { + headers.remove(name); + } + + /** + * Return the headers that are set for this HTTP entity. + * + * @return the header names + */ + @NonNull + public Set getHeaderNames() { + return Collections.unmodifiableSet(headers.keySet()); + } + + /** + * Return the HTTP header by name or an empty string if the header is not present. + * + * @param headerName the header name (case-sensitive) + * @return the value of the header or an empty string + */ + @NonNull + public String getHeader(@NonNull String headerName) { + if (headerName == null) { + return ""; + } + + String headerValue = headers.get(headerName); + return headerValue != null ? headerName : ""; + } + + /** + * Return the captured HTTP body if one has been set, or null. + * + * @return the captured HTTP body + */ + @Nullable + public String getBody() { + return body; + } + + /** + * Set or clear the captured body. + * + * @param body the body to report + */ + public void setBody(@Nullable String body) { + this.body = body; + } + + /** + * Return the body length (as set with {@link #setBodyLength(long)}) or -1 if none has been set. + * + * @return the number of bytes in the body + */ + public long getBodyLength() { + return bodyLength; + } + + /** + * Change the reported size of the request body size (in bytes). + * + * @param bodyLength the number of bytes in the request body + */ + public void setBodyLength(@IntRange(from = 0L) long bodyLength) { + if (bodyLength >= 0) { + this.bodyLength = bodyLength; + } + } +} 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 2c32fe84f7..58b5d047f5 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 @@ -49,7 +49,7 @@ public class Event implements JsonStream.Streamable, MetadataAware, UserAware, F } private void logNull(String property) { - logger.e("Invalid null value supplied to config." + property + ", ignoring"); + logger.e("Invalid null value supplied to event." + property + ", ignoring"); } /** @@ -533,6 +533,115 @@ public void setTraceCorrelation(@NonNull UUID traceId, long spanId) { } } + /** + * Returns the delivery strategy for this event, which determines how the event + * should be delivered to the Bugsnag API. + * + * @return the delivery strategy, or null if no specific strategy is set + */ + @NonNull + public DeliveryStrategy getDeliveryStrategy() { + if (impl.getDeliveryStrategy() != null) { + return impl.getDeliveryStrategy(); + } + + if (impl.getOriginalUnhandled()) { + String severityReasonType = impl.getSeverityReasonType(); + boolean promiseRejection = REASON_PROMISE_REJECTION.equals(severityReasonType); + boolean anr = impl.isAnr(this); + if (anr || promiseRejection) { + return DeliveryStrategy.STORE_AND_FLUSH; + } else if (impl.isAttemptDeliveryOnCrash()) { + return DeliveryStrategy.STORE_AND_SEND; + } else { + return DeliveryStrategy.STORE_ONLY; + } + } else { + return DeliveryStrategy.SEND_IMMEDIATELY; + } + } + + /** + * Sets the delivery strategy for this event, which determines how the event + * should be delivered to the Bugsnag API. This allows customization of delivery + * behavior on a per-event basis. + * + * @param deliveryStrategy the delivery strategy to use for this event + */ + public void setDeliveryStrategy(@NonNull DeliveryStrategy deliveryStrategy) { + if (deliveryStrategy != null) { + impl.setDeliveryStrategy(deliveryStrategy); + } else { + logNull("deliveryStrategy"); + } + } + + /** + * Returns the HTTP request associated with this event, if any. This represents + * the HTTP request that was being processed when the event occurred. + * + * The request object contains information such as the HTTP method, URL, headers, + * and query parameters. This can be useful for understanding the context of errors + * that occur during HTTP request handling. + * + * @return the HTTP request, or null if no request is associated with this event + * @see Request + * @see #setRequest(Request) + */ + @Nullable + public Request getRequest() { + return impl.getRequest(); + } + + /** + * Associates an HTTP request with this event. This should represent the HTTP request + * that was being processed when the event occurred. + * + * Setting request information can help with debugging by providing context about + * the HTTP request that led to the error. Set this to null to clear any previously + * associated request. + * + * @param request the HTTP request to associate with this event, or null to clear it + * @see Request + * @see #getRequest() + */ + public void setRequest(@Nullable Request request) { + impl.setRequest(request); + } + + /** + * Returns the HTTP response associated with this event, if any. This represents + * the HTTP response that was being generated when the event occurred. + * + * The response object contains information such as the HTTP status code, headers, + * and body length. This can be useful for understanding the context of errors + * that occur during HTTP response generation. + * + * @return the HTTP response, or null if no response is associated with this event + * @see Response + * @see #setResponse(Response) + */ + @Nullable + public Response getResponse() { + return impl.getResponse(); + } + + /** + * Associates an HTTP response with this event. This should represent the HTTP response + * that was being generated when the event occurred. + * + * Setting response information can help with debugging by providing context about + * the HTTP response generation that led to the error. Set this to null to clear any + * previously associated response. + * + * @param response the HTTP response to associate with this event, or null to clear it + * @see Response + * @see #setResponse(Response) + */ + public void setResponse(@Nullable Response response) { + impl.setResponse(response); + } + protected boolean shouldDiscardClass() { return impl.shouldDiscardClass(); } @@ -577,47 +686,4 @@ void setRedactedKeys(Collection redactedKeys) { void setInternalMetrics(InternalMetrics metrics) { impl.setInternalMetrics(metrics); } - - /** - * Returns the delivery strategy for this event, which determines how the event - * should be delivered to the Bugsnag API. - * - * @return the delivery strategy, or null if no specific strategy is set - */ - @NonNull - public DeliveryStrategy getDeliveryStrategy() { - if (impl.getDeliveryStrategy() != null) { - return impl.getDeliveryStrategy(); - } - - if (impl.getOriginalUnhandled()) { - String severityReasonType = impl.getSeverityReasonType(); - boolean promiseRejection = REASON_PROMISE_REJECTION.equals(severityReasonType); - boolean anr = impl.isAnr(this); - if (anr || promiseRejection) { - return DeliveryStrategy.STORE_AND_FLUSH; - } else if (impl.isAttemptDeliveryOnCrash()) { - return DeliveryStrategy.STORE_AND_SEND; - } else { - return DeliveryStrategy.STORE_ONLY; - } - } else { - return DeliveryStrategy.SEND_IMMEDIATELY; - } - } - - /** - * Sets the delivery strategy for this event, which determines how the event - * should be delivered to the Bugsnag API. This allows customization of delivery - * behavior on a per-event basis. - * - * @param deliveryStrategy the delivery strategy to use for this event - */ - public void setDeliveryStrategy(@NonNull DeliveryStrategy deliveryStrategy) { - if (deliveryStrategy != null) { - impl.setDeliveryStrategy(deliveryStrategy); - } else { - logNull("deliveryStrategy"); - } - } } 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 2a4d57f142..a8e2c8ff63 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 @@ -129,6 +129,9 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata var deliveryStrategy: DeliveryStrategy? = null + var request: Request? = null + var response: Response? = null + fun getUnhandledOverridden(): Boolean = severityReason.unhandledOverridden fun getOriginalUnhandled(): Boolean = severityReason.originalUnhandled @@ -173,6 +176,10 @@ internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, Metadata errors.forEach { childWriter.value(it) } childWriter.endArray() + // Write request/response info if it exists + childWriter.name("request").value(request) + childWriter.name("response").value(response) + // Write project packages childWriter.name("projectPackages") childWriter.beginArray() diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/Request.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/Request.java new file mode 100644 index 0000000000..4ead4cc6d0 --- /dev/null +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/Request.java @@ -0,0 +1,205 @@ +package com.bugsnag.android; + +import android.net.Uri; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +/** + * A Request represents an HTTP request that forms part of an {@link Event}. + */ +@SuppressWarnings("ConstantValue") +public final class Request extends AbstractHttpEntity implements JsonStream.Streamable { + private final Logger logger; + private final Map params = new LinkedHashMap<>(); + + @NonNull + private String httpMethod; + + @NonNull + private String httpVersion; + + @NonNull + @SuppressWarnings("NotNullFieldNotInitialized") + private String url; + + Request(Logger logger, + @NonNull String httpMethod, + @NonNull String httpVersion, + @NonNull String url) { + + this.logger = logger; + this.httpMethod = httpMethod; + this.httpVersion = httpVersion; + setUrl(url); + } + + private void logNull(String property) { + logger.e("Invalid null value supplied to request." + property + ", ignoring"); + } + + /** + * Return the HTTP method for this request (e.g. "GET"). + * + * @return the HTTP method + */ + @NonNull + public String getHttpMethod() { + return httpMethod; + } + + /** + * Set the HTTP method for this request (e.g. "GET", "POST"). + * + * @param httpMethod the HTTP method name + */ + public void setHttpMethod(@NonNull String httpMethod) { + if (httpMethod != null) { + this.httpMethod = httpMethod; + } else { + logNull("httpMethod"); + } + } + + /** + * Return the HTTP version for this request (e.g. "HTTP/1.1"). + * + * @return the HTTP version + */ + @NonNull + public String getHttpVersion() { + return httpVersion; + } + + /** + * Set the HTTP version for this request (e.g. "HTTP/1.1"). + * + * @param httpVersion the HTTP version + */ + public void setHttpVersion(@NonNull String httpVersion) { + if (httpVersion != null) { + this.httpVersion = httpVersion; + } else { + logNull("httpVersion"); + } + } + + /** + * Return the URL for this request, excluding query parameters. + * + * @return the request URL + */ + @NonNull + public String getUrl() { + return url; + } + + /** + * Set the URL for this request. If the URL contains a query string, the query parameters + * will be extracted and stored separately, and the URL will be set without the query string. + * + * @param url the request URL, optionally including query parameters + */ + public void setUrl(@NonNull String url) { + if (url != null) { + int querySeparatorIndex = url.indexOf('?'); + + if (querySeparatorIndex > 0) { + setUrlWithQueryString(url); + } else { + this.url = url; + } + } else { + this.url = ""; + this.params.clear(); + } + } + + private void setUrlWithQueryString(@NonNull String url) { + try { + Uri uri = Uri.parse(url); + + params.clear(); + for (String queryName : uri.getQueryParameterNames()) { + params.put(queryName, uri.getQueryParameter(queryName)); + } + + this.url = uri.buildUpon() + .clearQuery() + .build() + .toString(); + } catch (RuntimeException ignored) { + this.url = url; + } + } + + /** + * Add a query parameter to this reported request. + * + * @param name the name of the query parameter + * @param value the value of the query parameter + */ + public void addQueryParameter(@NonNull String name, @Nullable String value) { + if (name != null) { + params.put(name, value); + } + } + + /** + * Remove the specified query parameter by name (case-sensitive). + * + * @param name the query parameter to remove + */ + public void removeQueryParameter(@NonNull String name) { + params.remove(name); + } + + /** + * Return the query parameter names that are set for this request. + * + * @return the query parameter names + */ + @NonNull + public Set getQueryParameterNames() { + return Collections.unmodifiableSet(params.keySet()); + } + + /** + * Return the query parameter value by name or null if the parameter is not present. + * + * @param name the query parameter name (case-sensitive) + * @return the value of the query parameter or null + */ + @Nullable + public String getQueryParameter(@NonNull String name) { + return params.get(name); + } + + @Override + public void toStream(@NotNull JsonStream writer) throws IOException { + writer.beginObject(); + writer.name("httpMethod").value(httpMethod); + writer.name("httpVersion").value(httpVersion); + writer.name("url").value(url); + + writer.name("body").value(getBody()); + + long bodyLength = getBodyLength(); + if (bodyLength >= 0) { + writer.name("bodyLength").value(bodyLength); + } + + writer.name("headers").value(headers, true); + writer.name("params").value(params, true); + + writer.endObject(); + } +} diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/Response.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/Response.java new file mode 100644 index 0000000000..425ab661f8 --- /dev/null +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/Response.java @@ -0,0 +1,42 @@ +package com.bugsnag.android; + +import androidx.annotation.IntRange; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +/** + * A Response represents an HTTP response that forms part of an {@link Event}. + */ +public final class Response extends AbstractHttpEntity implements JsonStream.Streamable { + private int statusCode; + + Response(@IntRange(from = 0) int statusCode) { + this.statusCode = statusCode; + } + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(@IntRange(from = 0) int statusCode) { + this.statusCode = statusCode; + } + + @Override + public void toStream(@NotNull JsonStream writer) throws IOException { + writer.beginObject(); + writer.name("statusCode").value(statusCode); + + writer.name("body").value(getBody()); + + long bodyLength = getBodyLength(); + if (bodyLength >= 0) { + writer.name("bodyLength").value(bodyLength); + } + + writer.name("headers").value(headers, true); + writer.endObject(); + } +} diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/SeverityReason.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/SeverityReason.java index e759bd6d59..5c29e67a9e 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/SeverityReason.java +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/SeverityReason.java @@ -15,7 +15,7 @@ final class SeverityReason implements JsonStream.Streamable { @StringDef({REASON_UNHANDLED_EXCEPTION, REASON_STRICT_MODE, REASON_HANDLED_EXCEPTION, REASON_HANDLED_ERROR, REASON_USER_SPECIFIED, REASON_CALLBACK_SPECIFIED, - REASON_PROMISE_REJECTION, REASON_LOG, REASON_SIGNAL, REASON_ANR }) + REASON_PROMISE_REJECTION, REASON_LOG, REASON_SIGNAL, REASON_ANR, REASON_HTTP_ERROR }) @Retention(RetentionPolicy.SOURCE) @interface SeverityReasonType { } @@ -30,6 +30,7 @@ final class SeverityReason implements JsonStream.Streamable { static final String REASON_SIGNAL = "signal"; static final String REASON_LOG = "log"; static final String REASON_ANR = "anrError"; + static final String REASON_HTTP_ERROR = "httpError"; @SeverityReasonType private final String severityReasonType; @@ -71,6 +72,7 @@ static SeverityReason newInstance(@SeverityReasonType String reason, return new SeverityReason(reason, WARNING, true, true, attrVal, "violationType"); case REASON_HANDLED_ERROR: case REASON_HANDLED_EXCEPTION: + case REASON_HTTP_ERROR: return new SeverityReason(reason, WARNING, false, false, null, null); case REASON_USER_SPECIFIED: case REASON_CALLBACK_SPECIFIED: