diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f2234f1b3..5f12959872 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Add `lock` attribute to the `SentryStackFrame` protocol to better highlight offending frames in the UI ([#2761](https://github.com/getsentry/sentry-java/pull/2761)) - Enrich database spans with blocked main thread info ([#2760](https://github.com/getsentry/sentry-java/pull/2760)) +- Add `api_target` to `Request` and `data` to `Response` Protocols ([#2775](https://github.com/getsentry/sentry-java/pull/2775)) ## 6.21.0 diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 94a92dd72f..531f861838 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -3305,6 +3305,7 @@ public final class io/sentry/protocol/Request : io/sentry/JsonSerializable, io/s public fun ()V public fun (Lio/sentry/protocol/Request;)V public fun equals (Ljava/lang/Object;)Z + public fun getApiTarget ()Ljava/lang/String; public fun getBodySize ()Ljava/lang/Long; public fun getCookies ()Ljava/lang/String; public fun getData ()Ljava/lang/Object; @@ -3318,6 +3319,7 @@ public final class io/sentry/protocol/Request : io/sentry/JsonSerializable, io/s public fun getUrl ()Ljava/lang/String; public fun hashCode ()I public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun setApiTarget (Ljava/lang/String;)V public fun setBodySize (Ljava/lang/Long;)V public fun setCookies (Ljava/lang/String;)V public fun setData (Ljava/lang/Object;)V @@ -3338,6 +3340,7 @@ public final class io/sentry/protocol/Request$Deserializer : io/sentry/JsonDeser } public final class io/sentry/protocol/Request$JsonKeys { + public static final field API_TARGET Ljava/lang/String; public static final field BODY_SIZE Ljava/lang/String; public static final field COOKIES Ljava/lang/String; public static final field DATA Ljava/lang/String; @@ -3357,12 +3360,14 @@ public final class io/sentry/protocol/Response : io/sentry/JsonSerializable, io/ public fun (Lio/sentry/protocol/Response;)V public fun getBodySize ()Ljava/lang/Long; public fun getCookies ()Ljava/lang/String; + public fun getData ()Ljava/lang/Object; public fun getHeaders ()Ljava/util/Map; public fun getStatusCode ()Ljava/lang/Integer; public fun getUnknown ()Ljava/util/Map; public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V public fun setBodySize (Ljava/lang/Long;)V public fun setCookies (Ljava/lang/String;)V + public fun setData (Ljava/lang/Object;)V public fun setHeaders (Ljava/util/Map;)V public fun setStatusCode (Ljava/lang/Integer;)V public fun setUnknown (Ljava/util/Map;)V @@ -3377,6 +3382,7 @@ public final class io/sentry/protocol/Response$Deserializer : io/sentry/JsonDese public final class io/sentry/protocol/Response$JsonKeys { public static final field BODY_SIZE Ljava/lang/String; public static final field COOKIES Ljava/lang/String; + public static final field DATA Ljava/lang/String; public static final field HEADERS Ljava/lang/String; public static final field STATUS_CODE Ljava/lang/String; public fun ()V diff --git a/sentry/src/main/java/io/sentry/protocol/Request.java b/sentry/src/main/java/io/sentry/protocol/Request.java index 2e51a23197..8d5e0cda4b 100644 --- a/sentry/src/main/java/io/sentry/protocol/Request.java +++ b/sentry/src/main/java/io/sentry/protocol/Request.java @@ -109,6 +109,16 @@ public final class Request implements JsonUnknown, JsonSerializable { /** The fragment (anchor) of the request URL. */ private @Nullable String fragment; + /** + * The API target/specification that made the request. + * + *

Values can be `graphql`, `rest`, etc. + * + *

The data field should contain the request and response bodies based on its target + * specification. + */ + private @Nullable String apiTarget; + @SuppressWarnings("unused") private @Nullable Map unknown; @@ -126,6 +136,7 @@ public Request(final @NotNull Request request) { this.data = request.data; this.fragment = request.fragment; this.bodySize = request.bodySize; + this.apiTarget = request.apiTarget; } public @Nullable String getUrl() { @@ -220,12 +231,14 @@ public boolean equals(Object o) { && Objects.equals(headers, request.headers) && Objects.equals(env, request.env) && Objects.equals(bodySize, request.bodySize) - && Objects.equals(fragment, request.fragment); + && Objects.equals(fragment, request.fragment) + && Objects.equals(apiTarget, request.apiTarget); } @Override public int hashCode() { - return Objects.hash(url, method, queryString, cookies, headers, env, bodySize, fragment); + return Objects.hash( + url, method, queryString, cookies, headers, env, bodySize, fragment, apiTarget); } // region json @@ -241,6 +254,14 @@ public void setUnknown(@Nullable Map unknown) { this.unknown = unknown; } + public @Nullable String getApiTarget() { + return apiTarget; + } + + public void setApiTarget(final @Nullable String apiTarget) { + this.apiTarget = apiTarget; + } + public static final class JsonKeys { public static final String URL = "url"; public static final String METHOD = "method"; @@ -252,6 +273,7 @@ public static final class JsonKeys { public static final String OTHER = "other"; public static final String FRAGMENT = "fragment"; public static final String BODY_SIZE = "body_size"; + public static final String API_TARGET = "api_target"; } @Override @@ -286,7 +308,10 @@ public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) writer.name(JsonKeys.FRAGMENT).value(logger, fragment); } if (bodySize != null) { - writer.name(Response.JsonKeys.BODY_SIZE).value(logger, bodySize); + writer.name(JsonKeys.BODY_SIZE).value(logger, bodySize); + } + if (apiTarget != null) { + writer.name(JsonKeys.API_TARGET).value(logger, apiTarget); } if (unknown != null) { for (String key : unknown.keySet()) { @@ -346,9 +371,12 @@ public static final class Deserializer implements JsonDeserializer { case JsonKeys.FRAGMENT: request.fragment = reader.nextStringOrNull(); break; - case Response.JsonKeys.BODY_SIZE: + case JsonKeys.BODY_SIZE: request.bodySize = reader.nextLongOrNull(); break; + case JsonKeys.API_TARGET: + request.apiTarget = reader.nextStringOrNull(); + break; default: if (unknown == null) { unknown = new ConcurrentHashMap<>(); diff --git a/sentry/src/main/java/io/sentry/protocol/Response.java b/sentry/src/main/java/io/sentry/protocol/Response.java index d34b605d2d..dcfec08f46 100644 --- a/sentry/src/main/java/io/sentry/protocol/Response.java +++ b/sentry/src/main/java/io/sentry/protocol/Response.java @@ -37,6 +37,14 @@ public final class Response implements JsonUnknown, JsonSerializable { /** The body size in bytes */ private @Nullable Long bodySize; + /** + * Response data in any format that makes sense. + * + *

SDKs should discard large and binary bodies by default. Can be given as a string or + * structural data of any format. + */ + private @Nullable Object data; + @SuppressWarnings("unused") private @Nullable Map unknown; @@ -48,6 +56,7 @@ public Response(final @NotNull Response response) { this.unknown = CollectionUtils.newConcurrentHashMap(response.unknown); this.statusCode = response.statusCode; this.bodySize = response.bodySize; + this.data = response.data; } public @Nullable String getCookies() { @@ -93,6 +102,14 @@ public void setBodySize(final @Nullable Long bodySize) { this.bodySize = bodySize; } + public @Nullable Object getData() { + return data; + } + + public void setData(final @Nullable Object data) { + this.data = data; + } + // region json public static final class JsonKeys { @@ -100,6 +117,7 @@ public static final class JsonKeys { public static final String HEADERS = "headers"; public static final String STATUS_CODE = "status_code"; public static final String BODY_SIZE = "body_size"; + public static final String DATA = "data"; } @Override @@ -119,7 +137,9 @@ public void serialize(final @NotNull JsonObjectWriter writer, final @NotNull ILo if (bodySize != null) { writer.name(JsonKeys.BODY_SIZE).value(logger, bodySize); } - + if (data != null) { + writer.name(JsonKeys.DATA).value(logger, data); + } if (unknown != null) { for (final String key : unknown.keySet()) { final Object value = unknown.get(key); @@ -157,6 +177,9 @@ public static final class Deserializer implements JsonDeserializer { case JsonKeys.BODY_SIZE: response.bodySize = reader.nextLongOrNull(); break; + case JsonKeys.DATA: + response.data = reader.nextObjectOrNull(); + break; default: if (unknown == null) { unknown = new ConcurrentHashMap<>(); diff --git a/sentry/src/test/java/io/sentry/protocol/RequestSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/RequestSerializationTest.kt index 973c661b33..4aaa5423c3 100644 --- a/sentry/src/test/java/io/sentry/protocol/RequestSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/RequestSerializationTest.kt @@ -29,6 +29,7 @@ class RequestSerializationTest { ) bodySize = 1000 fragment = "fragment" + apiTarget = "graphql" } } private val fixture = Fixture() diff --git a/sentry/src/test/java/io/sentry/protocol/RequestTest.kt b/sentry/src/test/java/io/sentry/protocol/RequestTest.kt index 2acb3316d6..5cf1d68aae 100644 --- a/sentry/src/test/java/io/sentry/protocol/RequestTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/RequestTest.kt @@ -35,6 +35,7 @@ class RequestTest { assertEquals("unknown", clone.unknown!!["unknown"]) assertEquals(1000, clone.bodySize) assertEquals("fragment", clone.fragment) + assertEquals("graphql", clone.apiTarget) } @Test @@ -52,6 +53,7 @@ class RequestTest { request.unknown = newUnknown request.bodySize = 1001 request.fragment = "fragment2" + request.apiTarget = "graphql" assertEquals("get", clone.method) assertEquals("http://localhost:8080", clone.url) @@ -64,6 +66,7 @@ class RequestTest { assertEquals(1, clone.unknown!!.size) assertEquals(1000, clone.bodySize) assertEquals("fragment", clone.fragment) + assertEquals("graphql", clone.apiTarget) } @Test @@ -119,6 +122,7 @@ class RequestTest { setUnknown(unknown) bodySize = 1000 fragment = "fragment" + apiTarget = "graphql" } } } diff --git a/sentry/src/test/java/io/sentry/protocol/ResponseSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/ResponseSerializationTest.kt index 203b697aec..e278813d8d 100644 --- a/sentry/src/test/java/io/sentry/protocol/ResponseSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/ResponseSerializationTest.kt @@ -14,6 +14,9 @@ class ResponseSerializationTest { headers = mapOf("content-type" to "text/html") statusCode = 500 bodySize = 1000 + data = mapOf( + "d9d709db-b666-40cc-bcbb-093bb12aad26" to "1631d0e6-96b7-4632-85f8-ef69e8bcfb16" + ) unknown = mapOf("arbitrary_field" to "arbitrary") } } diff --git a/sentry/src/test/resources/json/request.json b/sentry/src/test/resources/json/request.json index d0eb6d9735..d744deac62 100644 --- a/sentry/src/test/resources/json/request.json +++ b/sentry/src/test/resources/json/request.json @@ -20,5 +20,6 @@ "669ff1c1-517b-46dc-a889-131555364a56": "89043294-f6e1-4e2e-b152-1fdf9b1102fc" }, "fragment": "fragment", - "body_size": 1000 + "body_size": 1000, + "api_target": "graphql" } diff --git a/sentry/src/test/resources/json/response.json b/sentry/src/test/resources/json/response.json index 9faf2b4183..af7d4ab767 100644 --- a/sentry/src/test/resources/json/response.json +++ b/sentry/src/test/resources/json/response.json @@ -5,5 +5,9 @@ }, "status_code": 500, "body_size": 1000, + "data": + { + "d9d709db-b666-40cc-bcbb-093bb12aad26": "1631d0e6-96b7-4632-85f8-ef69e8bcfb16" + }, "arbitrary_field": "arbitrary" }