(),
+ { resp: Response -> resp.headers.toMap() }
)
+ }
- // Extract response data if available
- val responseData = response?.let {
- val responseHeaders = it.headers.toMap()
- val (respBodySize, respBodyInfo) = extractBodyMetadata(
- it.body?.contentLength(),
- it.body?.contentType()
- )
-
- scopes.options.logger.log(
- io.sentry.SentryLevel.INFO,
- "SentryNetwork: Response - Status: ${it.code}, Headers count: ${responseHeaders.size}, Body size: $respBodySize, Body info: $respBodyInfo"
- )
-
- ReplayNetworkRequestOrResponse(
- respBodySize,
- respBodyInfo,
- responseHeaders
- )
- }
-
- // Determine final body sizes (prefer the explicit sizes passed in)
- val finalResponseBodySize = response?.let {
- val (respBodySize, _) = extractBodyMetadata(
- it.body?.contentLength(),
- it.body?.contentType()
- )
- responseBodySize ?: respBodySize
+ /** Extracts the body content from an OkHttp Response safely */
+ private fun Response.extractOkHttpResponseBody(): NetworkBody? {
+ return body?.let {
+ try {
+ val peekBody = peekBody(Long.MAX_VALUE)
+ val bodyString = peekBody.string()
+
+ // Try to parse as JSON first, fall back to string
+ when {
+ bodyString.isEmpty() -> null
+ bodyString.trimStart().startsWith("{") -> {
+ // Attempt JSON object parsing (simplified)
+ NetworkBody.JsonObject(mapOf("raw" to bodyString)) // Placeholder for now
+ }
+ bodyString.trimStart().startsWith("[") -> {
+ // Attempt JSON array parsing (simplified)
+ NetworkBody.JsonArray(listOf(bodyString)) // Placeholder for now
+ }
+ else -> NetworkBody.StringBody(bodyString)
+ }
+ } catch (e: Exception) {
+ // If body reading fails, log and return null
+ scopes.options.logger.log(
+ io.sentry.SentryLevel.DEBUG,
+ "Failed to read response body safely: ${e.message}"
+ )
+ null
+ }
}
-
- val networkData = NetworkRequestData(
- request.method,
- response?.code,
- requestBodySize ?: reqBodySize,
- finalResponseBodySize,
- requestData,
- responseData
- )
-
- scopes.options.logger.log(
- io.sentry.SentryLevel.INFO,
- "SentryNetwork: Created NetworkRequestData: $networkData"
- )
-
- return networkData
}
private fun finishSpan(
@@ -375,6 +389,7 @@ public open class SentryOkHttpInterceptor(
return false
}
+
/** The BeforeSpan callback */
public fun interface BeforeSpanCallback {
/**
diff --git a/sentry/src/main/java/io/sentry/util/network/NetworkBody.java b/sentry/src/main/java/io/sentry/util/network/NetworkBody.java
new file mode 100644
index 00000000000..f3dbe53e2d7
--- /dev/null
+++ b/sentry/src/main/java/io/sentry/util/network/NetworkBody.java
@@ -0,0 +1,68 @@
+package io.sentry.util.network;
+
+import java.util.List;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Represents the body content of a network request or response. Can be one of: JsonObject,
+ * JsonArray, or String.
+ *
+ * See https://github.com/getsentry/sentry-javascript/blob/develop/packages/replay-internal/src/types/request.ts
+ */
+public interface NetworkBody {
+
+ /** Represents a JSON object body (key-value pairs) */
+ public static final class JsonObject implements NetworkBody {
+ private final @NotNull Map value;
+
+ public JsonObject(@NotNull Map value) {
+ this.value = value;
+ }
+
+ public @NotNull Map getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return "JsonObject{" + value + '}';
+ }
+ }
+
+ /** Represents a JSON array body (ordered list) */
+ public static final class JsonArray implements NetworkBody {
+ private final @NotNull List