Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This file follows [Keepachangelog](https://keepachangelog.com/) format.
Please add your entries according to this format.

## Unreleased
* Added ability to log manual transactions. In order to do this call ChuckerCollector#saveTransaction(transaction: ManualHttpTransaction) method and pass ManualHttpTransaction entity to it.

### Added
* Decoding of request and response bodies can now be customized. In order to do this a `BodyDecoder` interface needs to be implemented and installed in the `ChuckerInterceptor` via `ChuckerInterceptor.addBinaryDecoder(decoder)` method. Decoded bodies are then displayed in the Chucker UI.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.chuckerteam.chucker.api

import android.content.Context
import com.chuckerteam.chucker.api.entity.ManualHttpTransaction

/**
* No-op implementation.
Expand All @@ -10,4 +11,12 @@ public class ChuckerCollector @JvmOverloads constructor(
context: Context,
public var showNotification: Boolean = true,
retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK
)
) {

/**
* No-op implementation.
*/
public fun saveTransaction(transaction: ManualHttpTransaction) {
// Empty method for the library-no-op artifact
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.chuckerteam.chucker.api.entity

/**
* No-op implementation.
*/
public data class ManualHttpTransaction(
public var requestDate: Long? = null,
public var responseDate: Long? = null,
public var tookMs: Long? = null,
public var protocol: String? = null,
public var method: String? = null,
public var url: String? = null,
public var host: String? = null,
public var path: String? = null,
public var scheme: String? = null,
public var responseTlsVersion: String? = null,
public var responseCipherSuite: String? = null,
public var requestPayloadSize: Long? = null,
public var requestContentType: String? = null,
public var requestHeaders: String? = null,
public var requestHeadersSize: Long? = null,
public var requestBody: String? = null,
public var isRequestBodyEncoded: Boolean = false,
public var responseCode: Int? = null,
public var responseMessage: String? = null,
public var error: String? = null,
public var responsePayloadSize: Long? = null,
public var responseContentType: String? = null,
public var responseHeaders: String? = null,
public var responseHeadersSize: Long? = null,
public var responseBody: String? = null,
public var isResponseBodyEncoded: Boolean = false,
public var responseImageData: ByteArray? = null
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.chuckerteam.chucker.api

import android.content.Context
import com.chuckerteam.chucker.api.entity.ManualHttpTransaction
import com.chuckerteam.chucker.internal.data.entity.HttpTransaction
import com.chuckerteam.chucker.internal.data.repository.RepositoryProvider
import com.chuckerteam.chucker.internal.support.NotificationHelper
Expand Down Expand Up @@ -63,4 +64,13 @@ public class ChuckerCollector @JvmOverloads constructor(
}
}
}

/**
* Call this method whenever you want to save a transaction that is not collected by Chucker interceptor
*
* @param transaction the manual transaction you want to save it manually
*/
public fun saveTransaction(transaction: ManualHttpTransaction) {
onRequestSent(transaction.convertToHttpTransaction())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.chuckerteam.chucker.api.entity

import com.chuckerteam.chucker.internal.data.entity.HttpTransaction

/**
* Represent Manual Http transaction that developer want to populate as an custom http transaction
*/
public data class ManualHttpTransaction(
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need another class here?

Copy link
Author

@aliab aliab Aug 3, 2022

Choose a reason for hiding this comment

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

I didn't want to move the HttpTransaction class to the API package or expose it to the developer. I could use a builder pattern to build transaction objects or create a method with a bunch of args in the ChuckerCollector class.
But both of these mentioned approaches have their downsides regarding logging the data. In this implemented approach, to log a transaction's start and end information, the developer no longer needs to store the data in a separate data store and can create the model and fill it in during transactions. In the end, the developer can save the object in the chucker.

public var requestDate: Long? = null,
public var responseDate: Long? = null,
public var tookMs: Long? = null,
public var protocol: String? = null,
public var method: String? = null,
public var url: String? = null,
public var host: String? = null,
public var path: String? = null,
public var scheme: String? = null,
public var responseTlsVersion: String? = null,
public var responseCipherSuite: String? = null,
public var requestPayloadSize: Long? = null,
public var requestContentType: String? = null,
public var requestHeaders: String? = null,
public var requestHeadersSize: Long? = null,
public var requestBody: String? = null,
public var isRequestBodyEncoded: Boolean = false,
public var responseCode: Int? = null,
public var responseMessage: String? = null,
public var error: String? = null,
public var responsePayloadSize: Long? = null,
public var responseContentType: String? = null,
public var responseHeaders: String? = null,
public var responseHeadersSize: Long? = null,
public var responseBody: String? = null,
public var isResponseBodyEncoded: Boolean = false,
public var responseImageData: ByteArray? = null
) {

/**
* this will convert this class to HttpTransaction to be able to save it on database as a real
* transaction.
*/
internal fun convertToHttpTransaction(): HttpTransaction {
return HttpTransaction(
0,
requestDate,
responseDate,
tookMs,
protocol,
method,
url,
host,
path,
scheme,
responseTlsVersion,
responseCipherSuite,
requestPayloadSize,
requestContentType,
requestHeaders,
requestHeadersSize,
requestBody,
isRequestBodyEncoded,
responseCode,
responseMessage,
error,
responsePayloadSize,
responseContentType,
responseHeaders,
responseHeadersSize,
responseBody,
isResponseBodyEncoded,
responseImageData
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import android.text.method.LinkMovementMethod
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.chuckerteam.chucker.api.Chucker
import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.RetentionManager
import com.chuckerteam.chucker.sample.databinding.ActivityMainSampleBinding

private val interceptorTypeSelector = InterceptorTypeSelector()
Expand All @@ -14,12 +16,25 @@ class MainActivity : AppCompatActivity() {

private lateinit var mainBinding: ActivityMainSampleBinding

private val chuckerCollector: ChuckerCollector by lazy {
ChuckerCollector(
context = applicationContext,
showNotification = true,
retentionPeriod = RetentionManager.Period.ONE_HOUR
)
}

private val client by lazy {
createOkHttpClient(applicationContext, interceptorTypeSelector)
createOkHttpClient(applicationContext, interceptorTypeSelector, chuckerCollector)
}

private val httpTasks by lazy {
listOf(HttpBinHttpTask(client), DummyImageHttpTask(client), PostmanEchoHttpTask(client))
listOf(
HttpBinHttpTask(client),
DummyImageHttpTask(client),
PostmanEchoHttpTask(client),
ManualTransactionTask(chuckerCollector)
)
}

override fun onCreate(savedInstanceState: Bundle?) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.chuckerteam.chucker.sample

import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.entity.ManualHttpTransaction

class ManualTransactionTask(
private val chuckerCollector: ChuckerCollector
) : HttpTask {

override fun run() {
val responseBody = "Some Custom response body!"
chuckerCollector.saveTransaction(
transaction = ManualHttpTransaction(
requestDate = System.currentTimeMillis(),
responseDate = System.currentTimeMillis(),
protocol = "CustomProtocol",
method = "Custom Method",
responseContentType = "text/html; charset=UTF-8",
requestContentType = "text/html; charset=UTF-8",
scheme = "http",
isResponseBodyEncoded = false,
tookMs = 1000,
responseCode = 200,
responseMessage = "OK",
responseBody = responseBody,
isRequestBodyEncoded = false,
responsePayloadSize = responseBody.toByteArray().size.toLong(),
host = "Custom HOST",
url = "http://customUrl.com/",
path = "/custom",
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ const val SEGMENT_SIZE = 8_192L
fun createOkHttpClient(
context: Context,
interceptorTypeProvider: InterceptorType.Provider,
): OkHttpClient {
val collector = ChuckerCollector(
collector: ChuckerCollector = ChuckerCollector(
context = context,
showNotification = true,
retentionPeriod = RetentionManager.Period.ONE_HOUR
)
): OkHttpClient {


@Suppress("MagicNumber")
val chuckerInterceptor = ChuckerInterceptor.Builder(context)
Expand Down