From bc946fbd2a0d519ddd7215da90e7627b7e9299a1 Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Tue, 8 Oct 2019 00:34:19 +0200 Subject: [PATCH 01/14] Add a DSL to configure features HTTP / Errors --- .../chucker/api/ChuckerCollector.kt | 29 ++++++---- .../chucker/api/ChuckerInterceptor.kt | 21 +++++-- .../chucker/api/RetentionManager.kt | 14 +++-- .../chucker/api/config/ErrorsFeature.kt | 6 ++ .../chuckerteam/chucker/api/config/Feature.kt | 3 + .../chucker/api/config/HttpFeature.kt | 9 +++ .../chucker/api/dsl/Configuration.dsl.kt | 55 +++++++++++++++++++ .../internal/support/FeatureManager.kt | 16 ++++++ sample/src/main/AndroidManifest.xml | 1 + .../chucker/sample/ChuckerApplication.kt | 23 ++++++++ .../chucker/sample/HttpBinClient.kt | 4 +- 11 files changed, 155 insertions(+), 26 deletions(-) create mode 100644 library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt create mode 100644 library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt create mode 100644 library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt create mode 100644 library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt create mode 100644 library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt create mode 100644 sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt diff --git a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt index 293802010..c177f8606 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt @@ -1,9 +1,12 @@ package com.chuckerteam.chucker.api import android.content.Context +import com.chuckerteam.chucker.api.config.ErrorsFeature +import com.chuckerteam.chucker.api.config.HttpFeature import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.data.entity.RecordedThrowable import com.chuckerteam.chucker.internal.data.repository.RepositoryProvider +import com.chuckerteam.chucker.internal.support.FeatureManager import com.chuckerteam.chucker.internal.support.NotificationHelper /** @@ -12,18 +15,14 @@ import com.chuckerteam.chucker.internal.support.NotificationHelper * provide it to * * @param context An Android Context - * @param showNotification Control whether a notification is shown while HTTP activity - * is recorded. - * @param retentionManager Set the retention period for HTTP transaction data captured - * by this collector. The default is one week. */ -class ChuckerCollector @JvmOverloads constructor( - context: Context, - var showNotification: Boolean = true, - retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK +class ChuckerCollector( + context: Context ) { - private val retentionManager: RetentionManager = RetentionManager(context, retentionPeriod) + private val retentionManager: RetentionManager = RetentionManager(context) private val notificationHelper: NotificationHelper = NotificationHelper(context) + private val httpFeature: HttpFeature = FeatureManager.find() + private val errorsFeature: ErrorsFeature = FeatureManager.find() init { RepositoryProvider.initialize(context) @@ -35,9 +34,11 @@ class ChuckerCollector @JvmOverloads constructor( * @param throwable The triggered [Throwable] */ fun onError(tag: String, throwable: Throwable) { + if (!errorsFeature.enabled) return + val recordedThrowable = RecordedThrowable(tag, throwable) RepositoryProvider.throwable().saveThrowable(recordedThrowable) - if (showNotification) { + if (errorsFeature.showNotification) { notificationHelper.show(recordedThrowable) } retentionManager.doMaintenance() @@ -48,8 +49,10 @@ class ChuckerCollector @JvmOverloads constructor( * @param transaction The HTTP transaction sent */ internal fun onRequestSent(transaction: HttpTransaction) { + if (!httpFeature.enabled) return + RepositoryProvider.transaction().insertTransaction(transaction) - if (showNotification) { + if (httpFeature.showNotification) { notificationHelper.show(transaction) } retentionManager.doMaintenance() @@ -61,8 +64,10 @@ class ChuckerCollector @JvmOverloads constructor( * @param transaction The sent HTTP transaction completed with the response */ internal fun onResponseReceived(transaction: HttpTransaction) { + if (!httpFeature.enabled) return + val updated = RepositoryProvider.transaction().updateTransaction(transaction) - if (showNotification && updated > 0) { + if (httpFeature.showNotification && updated > 0) { notificationHelper.show(transaction) } } diff --git a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt index 6e151d5ff..04a2bcf9c 100755 --- a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt @@ -3,18 +3,21 @@ package com.chuckerteam.chucker.api import android.content.Context import android.util.Log import com.chuckerteam.chucker.api.Chucker.LOG_TAG +import com.chuckerteam.chucker.api.config.HttpFeature import com.chuckerteam.chucker.internal.data.entity.HttpTransaction +import com.chuckerteam.chucker.internal.support.FeatureManager import com.chuckerteam.chucker.internal.support.IOUtils import com.chuckerteam.chucker.internal.support.hasBody -import java.io.IOException -import java.nio.charset.Charset -import java.nio.charset.UnsupportedCharsetException -import java.util.concurrent.TimeUnit import okhttp3.Headers import okhttp3.Interceptor +import okhttp3.Request import okhttp3.Response import okio.Buffer import okio.BufferedSource +import java.io.IOException +import java.nio.charset.Charset +import java.nio.charset.UnsupportedCharsetException +import java.util.concurrent.TimeUnit private const val MAX_BLOB_SIZE = 1000_000L @@ -38,6 +41,7 @@ class ChuckerInterceptor @JvmOverloads constructor( ) : Interceptor { private val io: IOUtils = IOUtils(context) + private val httpFeature: HttpFeature = FeatureManager.find() fun redactHeader(name: String) = apply { headersToRedact.add(name) @@ -47,8 +51,15 @@ class ChuckerInterceptor @JvmOverloads constructor( @Suppress("LongMethod", "ComplexMethod") override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() - val requestBody = request.body() + return when { + httpFeature.enabled -> captureTransaction(request, chain) + else -> chain.proceed(request) + } + } + + private fun captureTransaction(request: Request, chain: Interceptor.Chain): Response { + val requestBody = request.body() val transaction = HttpTransaction() transaction.apply { requestDate = System.currentTimeMillis() diff --git a/library/src/main/java/com/chuckerteam/chucker/api/RetentionManager.kt b/library/src/main/java/com/chuckerteam/chucker/api/RetentionManager.kt index e68dfbbc5..e1d93e31f 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/RetentionManager.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/RetentionManager.kt @@ -4,29 +4,31 @@ import android.content.Context import android.content.SharedPreferences import android.util.Log import com.chuckerteam.chucker.api.Chucker.LOG_TAG +import com.chuckerteam.chucker.api.config.HttpFeature import com.chuckerteam.chucker.internal.data.repository.RepositoryProvider +import com.chuckerteam.chucker.internal.support.FeatureManager import java.util.concurrent.TimeUnit /** * Class responsible of holding the logic for the retention of your HTTP transactions * and your throwable. You can customize how long data should be stored here. * @param context An Android Context - * @param retentionPeriod A [Period] to specify the retention of data. Default 1 week. */ @Suppress("MagicNumber") -class RetentionManager @JvmOverloads constructor( - context: Context, - retentionPeriod: Period = Period.ONE_WEEK +class RetentionManager( + context: Context ) { + private val httpFeature: HttpFeature = FeatureManager.find() + // The actual retention period in milliseconds (default to ONE_WEEK) - private val period: Long = toMillis(retentionPeriod) + private val period: Long = toMillis(httpFeature.retentionPeriod) // How often the cleanup should happen private val cleanupFrequency: Long private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, 0) init { - cleanupFrequency = if (retentionPeriod == Period.ONE_HOUR) + cleanupFrequency = if (httpFeature.retentionPeriod == Period.ONE_HOUR) TimeUnit.MINUTES.toMillis(30) else TimeUnit.HOURS.toMillis(2) diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt new file mode 100644 index 000000000..46c99d491 --- /dev/null +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt @@ -0,0 +1,6 @@ +package com.chuckerteam.chucker.api.config + +class ErrorsFeature( + val enabled: Boolean, + val showNotification: Boolean +) : Feature diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt new file mode 100644 index 000000000..5f0a17aac --- /dev/null +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt @@ -0,0 +1,3 @@ +package com.chuckerteam.chucker.api.config + +interface Feature diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt new file mode 100644 index 000000000..d6e7a30ff --- /dev/null +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -0,0 +1,9 @@ +package com.chuckerteam.chucker.api.config + +import com.chuckerteam.chucker.api.RetentionManager + +class HttpFeature( + val enabled: Boolean, + val showNotification: Boolean, + val retentionPeriod: RetentionManager.Period +) : Feature diff --git a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt new file mode 100644 index 000000000..c162ea074 --- /dev/null +++ b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt @@ -0,0 +1,55 @@ +package com.chuckerteam.chucker.api.dsl + +import com.chuckerteam.chucker.api.RetentionManager +import com.chuckerteam.chucker.api.config.ErrorsFeature +import com.chuckerteam.chucker.api.config.HttpFeature +import com.chuckerteam.chucker.internal.support.FeatureManager + +@DslMarker +annotation class ChuckerConfig + +@ChuckerConfig +fun configureChucker(config: ChuckerConfigBuilder.() -> Unit) { + ChuckerConfigBuilder().apply(config).build() +} + +@ChuckerConfig +class ChuckerConfigBuilder { + + private var http: HttpFeature = HttpFeatureBuilder().build() + private var errors: ErrorsFeature = ErrorsFeatureBuilder().build() + + @ChuckerConfig + fun http(block: HttpFeatureBuilder.() -> Unit) { + http = HttpFeatureBuilder().apply(block).build() + } + + @ChuckerConfig + fun error(block: ErrorsFeatureBuilder.() -> Unit) { + errors = ErrorsFeatureBuilder().apply(block).build() + } + + fun build() { + FeatureManager.configure(http) + FeatureManager.configure(errors) + } +} + +@ChuckerConfig +class HttpFeatureBuilder { + var enabled: Boolean = true + var showNotification: Boolean = true + var retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK + + fun build(): HttpFeature = + HttpFeature(enabled, showNotification, retentionPeriod) +} + +@ChuckerConfig +class ErrorsFeatureBuilder { + var enabled: Boolean = true + var showNotification: Boolean = true + + fun build(): ErrorsFeature = + ErrorsFeature(enabled, showNotification) +} \ No newline at end of file diff --git a/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt b/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt new file mode 100644 index 000000000..c0ae84453 --- /dev/null +++ b/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt @@ -0,0 +1,16 @@ +package com.chuckerteam.chucker.internal.support + +import com.chuckerteam.chucker.api.config.Feature + +internal object FeatureManager { + + private val features = mutableListOf() + + fun configure(feature: Feature) { + features.add(feature) + } + + inline fun find(): T { + return features.first { it is T } as T + } +} \ No newline at end of file diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index ba96ef368..6684d2994 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -21,6 +21,7 @@ Date: Tue, 15 Oct 2019 13:57:45 +0200 Subject: [PATCH 02/14] Show tabs for enabled features only --- .../chucker/api/config/ErrorsFeature.kt | 24 ++++++++++++++++--- .../chuckerteam/chucker/api/config/Feature.kt | 13 +++++++++- .../chucker/api/config/HttpFeature.kt | 21 ++++++++++++++-- .../internal/support/FeatureManager.kt | 14 ++++++++++- .../chucker/internal/ui/HomePageAdapter.kt | 21 ++++------------ .../chucker/internal/ui/MainActivity.kt | 13 +++------- .../chucker/sample/ChuckerApplication.kt | 4 ++-- 7 files changed, 75 insertions(+), 35 deletions(-) diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt index 46c99d491..3404d102e 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt @@ -1,6 +1,24 @@ package com.chuckerteam.chucker.api.config +import android.content.Context +import androidx.fragment.app.Fragment +import com.chuckerteam.chucker.R +import com.chuckerteam.chucker.api.Chucker +import com.chuckerteam.chucker.internal.ui.error.ErrorListFragment + class ErrorsFeature( - val enabled: Boolean, - val showNotification: Boolean -) : Feature + override val enabled: Boolean, + val showNotification: Boolean +) : Feature { + override val name: Int = R.string.chucker_tab_errors + + override val tag: Int = Chucker.SCREEN_ERROR + + override fun newFragment(): Fragment { + return ErrorListFragment.newInstance() + } + + override fun dismissNotification(context: Context) { + Chucker.dismissErrorsNotification(context) + } +} diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt index 5f0a17aac..ee427c682 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt @@ -1,3 +1,14 @@ package com.chuckerteam.chucker.api.config -interface Feature +import android.content.Context +import androidx.annotation.StringRes +import androidx.fragment.app.Fragment + +interface Feature { + @get:StringRes + val name: Int + val tag: Int + val enabled: Boolean + fun newFragment(): Fragment + fun dismissNotification(context: Context) +} diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index d6e7a30ff..83b41b952 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -1,9 +1,26 @@ package com.chuckerteam.chucker.api.config +import android.content.Context +import androidx.fragment.app.Fragment +import com.chuckerteam.chucker.R +import com.chuckerteam.chucker.api.Chucker import com.chuckerteam.chucker.api.RetentionManager +import com.chuckerteam.chucker.internal.ui.transaction.TransactionListFragment class HttpFeature( - val enabled: Boolean, + override val enabled: Boolean, val showNotification: Boolean, val retentionPeriod: RetentionManager.Period -) : Feature +) : Feature { + override val name: Int = R.string.chucker_tab_network + + override val tag: Int = Chucker.SCREEN_ERROR + + override fun newFragment(): Fragment { + return TransactionListFragment.newInstance() + } + + override fun dismissNotification(context: Context) { + Chucker.dismissTransactionsNotification(context) + } +} diff --git a/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt b/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt index c0ae84453..54b642add 100644 --- a/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt +++ b/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt @@ -13,4 +13,16 @@ internal object FeatureManager { inline fun find(): T { return features.first { it is T } as T } -} \ No newline at end of file + + fun countEnabledFeatures(): Int { + return features.count { it.enabled } + } + + fun getAt(position: Int): Feature { + return features.filter { it.enabled }[position] + } + + fun getPositionOf(screenToShow: Int): Int { + return features.filter { it.enabled }.indexOfFirst { it.tag == screenToShow } + } +} diff --git a/library/src/main/java/com/chuckerteam/chucker/internal/ui/HomePageAdapter.kt b/library/src/main/java/com/chuckerteam/chucker/internal/ui/HomePageAdapter.kt index e03e1997d..00b39d507 100644 --- a/library/src/main/java/com/chuckerteam/chucker/internal/ui/HomePageAdapter.kt +++ b/library/src/main/java/com/chuckerteam/chucker/internal/ui/HomePageAdapter.kt @@ -4,31 +4,20 @@ import android.content.Context import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentStatePagerAdapter -import com.chuckerteam.chucker.R -import com.chuckerteam.chucker.internal.ui.error.ErrorListFragment -import com.chuckerteam.chucker.internal.ui.transaction.TransactionListFragment +import com.chuckerteam.chucker.internal.support.FeatureManager import java.lang.ref.WeakReference internal class HomePageAdapter(context: Context, fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { private val context: WeakReference = WeakReference(context) - override fun getItem(position: Int): Fragment = if (position == SCREEN_HTTP_INDEX) { - TransactionListFragment.newInstance() - } else { - ErrorListFragment.newInstance() - } + override fun getItem(position: Int): Fragment = + FeatureManager.getAt(position).newFragment() - override fun getCount(): Int = 2 + override fun getCount(): Int = FeatureManager.countEnabledFeatures() override fun getPageTitle(position: Int): CharSequence? = - context.get()?.getString( - if (position == SCREEN_HTTP_INDEX) { - R.string.chucker_tab_network - } else { - R.string.chucker_tab_errors - } - ) + context.get()?.getString(FeatureManager.getAt(position).name) companion object { const val SCREEN_HTTP_INDEX = 0 diff --git a/library/src/main/java/com/chuckerteam/chucker/internal/ui/MainActivity.kt b/library/src/main/java/com/chuckerteam/chucker/internal/ui/MainActivity.kt index 84e71578f..9d274ecc6 100644 --- a/library/src/main/java/com/chuckerteam/chucker/internal/ui/MainActivity.kt +++ b/library/src/main/java/com/chuckerteam/chucker/internal/ui/MainActivity.kt @@ -21,6 +21,7 @@ import androidx.appcompat.widget.Toolbar import androidx.viewpager.widget.ViewPager import com.chuckerteam.chucker.R import com.chuckerteam.chucker.api.Chucker +import com.chuckerteam.chucker.internal.support.FeatureManager import com.chuckerteam.chucker.internal.ui.error.ErrorActivity import com.chuckerteam.chucker.internal.ui.error.ErrorAdapter import com.chuckerteam.chucker.internal.ui.transaction.TransactionActivity @@ -53,11 +54,7 @@ class MainActivity : viewPager.addOnPageChangeListener(object : TabLayout.TabLayoutOnPageChangeListener(tabLayout) { override fun onPageSelected(position: Int) { super.onPageSelected(position) - if (position == 0) { - Chucker.dismissTransactionsNotification(this@MainActivity) - } else { - Chucker.dismissErrorsNotification(this@MainActivity) - } + FeatureManager.getAt(position).dismissNotification(this@MainActivity) } }) consumeIntent(intent) @@ -74,11 +71,7 @@ class MainActivity : private fun consumeIntent(intent: Intent) { // Get the screen to show, by default => HTTP val screenToShow = intent.getIntExtra(EXTRA_SCREEN, Chucker.SCREEN_HTTP) - if (screenToShow == Chucker.SCREEN_HTTP) { - viewPager.currentItem = HomePageAdapter.SCREEN_HTTP_INDEX - } else { - viewPager.currentItem = HomePageAdapter.SCREEN_ERROR_INDEX - } + viewPager.currentItem = FeatureManager.getPositionOf(screenToShow) } override fun onErrorClick(throwableId: Long, position: Int) { diff --git a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt index 67d1989dc..ddfb025db 100644 --- a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt +++ b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt @@ -11,12 +11,12 @@ class ChuckerApplication : Application() { configureChucker { http { - enabled = false + enabled = true showNotification = true retentionPeriod = RetentionManager.Period.ONE_HOUR } error { - enabled = false + enabled = true } } } From d8bc9808afeb7dcd1d4e3fd375f71a8a8544e8b3 Mon Sep 17 00:00:00 2001 From: Olivier Perez Date: Tue, 15 Oct 2019 14:35:42 +0200 Subject: [PATCH 03/14] Some help for Travis-CI --- .../chucker/api/ChuckerInterceptor.kt | 108 ++++++++++-------- .../chucker/api/config/HttpFeature.kt | 6 +- .../chucker/api/dsl/Configuration.dsl.kt | 6 +- 3 files changed, 65 insertions(+), 55 deletions(-) diff --git a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt index 04a2bcf9c..a2fa3e62a 100755 --- a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt @@ -8,16 +8,16 @@ import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.support.FeatureManager import com.chuckerteam.chucker.internal.support.IOUtils import com.chuckerteam.chucker.internal.support.hasBody +import java.io.IOException +import java.nio.charset.Charset +import java.nio.charset.UnsupportedCharsetException +import java.util.concurrent.TimeUnit import okhttp3.Headers import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response import okio.Buffer import okio.BufferedSource -import java.io.IOException -import java.nio.charset.Charset -import java.nio.charset.UnsupportedCharsetException -import java.util.concurrent.TimeUnit private const val MAX_BLOB_SIZE = 1000_000L @@ -52,44 +52,15 @@ class ChuckerInterceptor @JvmOverloads constructor( override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() - return when { - httpFeature.enabled -> captureTransaction(request, chain) - else -> chain.proceed(request) + return if (httpFeature.enabled) { + captureTransaction(request, chain) + } else { + chain.proceed(request) } } private fun captureTransaction(request: Request, chain: Interceptor.Chain): Response { - val requestBody = request.body() - val transaction = HttpTransaction() - transaction.apply { - requestDate = System.currentTimeMillis() - method = request.method() - populateUrl(request.url().toString()) - setRequestHeaders(request.headers()) - requestContentType = requestBody?.contentType()?.toString() - requestContentLength = requestBody?.contentLength() ?: 0L - } - - val encodingIsSupported = io.bodyHasSupportedEncoding(request.headers().get("Content-Encoding")) - transaction.isRequestBodyPlainText = encodingIsSupported - - if (requestBody != null && encodingIsSupported) { - val source = io.getNativeSource(Buffer(), io.bodyIsGzipped(request.headers().get("Content-Encoding"))) - val buffer = source.buffer() - requestBody.writeTo(buffer) - var charset: Charset = UTF8 - val contentType = requestBody.contentType() - if (contentType != null) { - charset = contentType.charset(UTF8) ?: UTF8 - } - if (io.isPlaintext(buffer)) { - val content = io.readFromBuffer(buffer, charset, maxContentLength) - transaction.requestBody = content - } else { - transaction.isResponseBodyPlainText = false - } - } - + val transaction = captureRequest(request) collector.onRequestSent(transaction) val startNs = System.nanoTime() @@ -137,17 +108,7 @@ class ChuckerInterceptor @JvmOverloads constructor( return response } } - if (io.isPlaintext(buffer)) { - val content = io.readFromBuffer(buffer.clone(), charset, maxContentLength) - transaction.responseBody = content - } else { - transaction.isResponseBodyPlainText = false - - if (transaction.responseContentType?.contains("image") == true && buffer.size() < MAX_BLOB_SIZE) { - transaction.responseImageData = buffer.clone().readByteArray() - } - } - transaction.responseContentLength = buffer.size() + transaction.completeWithBody(buffer, charset) } collector.onResponseReceived(transaction) @@ -155,6 +116,41 @@ class ChuckerInterceptor @JvmOverloads constructor( return response } + private fun captureRequest(request: Request): HttpTransaction { + val requestBody = request.body() + val transaction = HttpTransaction() + + transaction.apply { + requestDate = System.currentTimeMillis() + method = request.method() + populateUrl(request.url().toString()) + setRequestHeaders(request.headers()) + requestContentType = requestBody?.contentType()?.toString() + requestContentLength = requestBody?.contentLength() ?: 0L + } + + val encodingIsSupported = io.bodyHasSupportedEncoding(request.headers().get("Content-Encoding")) + transaction.isRequestBodyPlainText = encodingIsSupported + + if (requestBody != null && encodingIsSupported) { + val source = io.getNativeSource(Buffer(), io.bodyIsGzipped(request.headers().get("Content-Encoding"))) + val buffer = source.buffer() + requestBody.writeTo(buffer) + var charset: Charset = UTF8 + val contentType = requestBody.contentType() + if (contentType != null) { + charset = contentType.charset(UTF8) ?: UTF8 + } + if (io.isPlaintext(buffer)) { + val content = io.readFromBuffer(buffer, charset, maxContentLength) + transaction.requestBody = content + } else { + transaction.isResponseBodyPlainText = false + } + } + return transaction + } + /** Overrides all the headers in [headersToRedact] with a `**` */ private fun filterHeaders(headers: Headers): Headers { val builder = headers.newBuilder() @@ -182,6 +178,20 @@ class ChuckerInterceptor @JvmOverloads constructor( return response.body()!!.source() } + private fun HttpTransaction.completeWithBody(buffer: Buffer, charset: Charset) { + if (io.isPlaintext(buffer)) { + val content = io.readFromBuffer(buffer.clone(), charset, maxContentLength) + this.responseBody = content + } else { + this.isResponseBodyPlainText = false + + if (this.responseContentType?.contains("image") == true && buffer.size() < MAX_BLOB_SIZE) { + this.responseImageData = buffer.clone().readByteArray() + } + } + this.responseContentLength = buffer.size() + } + companion object { private val UTF8 = Charset.forName("UTF-8") } diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index 83b41b952..dd296ba3d 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -8,9 +8,9 @@ import com.chuckerteam.chucker.api.RetentionManager import com.chuckerteam.chucker.internal.ui.transaction.TransactionListFragment class HttpFeature( - override val enabled: Boolean, - val showNotification: Boolean, - val retentionPeriod: RetentionManager.Period + override val enabled: Boolean, + val showNotification: Boolean, + val retentionPeriod: RetentionManager.Period ) : Feature { override val name: Int = R.string.chucker_tab_network diff --git a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt index c162ea074..4db9f7a4f 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt @@ -42,7 +42,7 @@ class HttpFeatureBuilder { var retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK fun build(): HttpFeature = - HttpFeature(enabled, showNotification, retentionPeriod) + HttpFeature(enabled, showNotification, retentionPeriod) } @ChuckerConfig @@ -51,5 +51,5 @@ class ErrorsFeatureBuilder { var showNotification: Boolean = true fun build(): ErrorsFeature = - ErrorsFeature(enabled, showNotification) -} \ No newline at end of file + ErrorsFeature(enabled, showNotification) +} From 65f75b90363648d8b838aebadc12adddbd077bee Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Tue, 15 Oct 2019 21:32:07 +0200 Subject: [PATCH 04/14] Add DSL in no-op API --- .../chucker/api/config/ErrorsFeature.kt | 17 ++++++++++ .../chuckerteam/chucker/api/config/Feature.kt | 11 ++++++ .../chucker/api/config/HttpFeature.kt | 19 +++++++++++ .../chucker/api/dsl/Configuration.dsl.kt | 34 +++++++++++++++++++ .../com/chuckerteam/chucker/internal/NoOp.kt | 5 +++ .../chucker/sample/ChuckerApplication.kt | 2 +- 6 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt create mode 100644 library-no-op/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt create mode 100644 library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt create mode 100644 library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt create mode 100644 library-no-op/src/main/java/com/chuckerteam/chucker/internal/NoOp.kt diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt new file mode 100644 index 000000000..7687f4ce5 --- /dev/null +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt @@ -0,0 +1,17 @@ +package com.chuckerteam.chucker.api.config + +import android.content.Context +import com.chuckerteam.chucker.internal.notImplemented + +class ErrorsFeature( + override val enabled: Boolean, + val showNotification: Boolean +) : Feature { + override val name: Int = notImplemented() + + override val tag: Int = notImplemented() + + override fun newFragment() = notImplemented() + + override fun dismissNotification(context: Context) = notImplemented() +} diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt new file mode 100644 index 000000000..378e99f3c --- /dev/null +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt @@ -0,0 +1,11 @@ +package com.chuckerteam.chucker.api.config + +import android.content.Context + +interface Feature { + val name: Int + val tag: Int + val enabled: Boolean + fun newFragment(): Nothing + fun dismissNotification(context: Context) +} diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt new file mode 100644 index 000000000..2392f9b73 --- /dev/null +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -0,0 +1,19 @@ +package com.chuckerteam.chucker.api.config + +import android.content.Context +import com.chuckerteam.chucker.api.RetentionManager +import com.chuckerteam.chucker.internal.notImplemented + +class HttpFeature( + override val enabled: Boolean, + val showNotification: Boolean, + val retentionPeriod: RetentionManager.Period +) : Feature { + override val name: Int = notImplemented() + + override val tag: Int = notImplemented() + + override fun newFragment() = notImplemented() + + override fun dismissNotification(context: Context) = notImplemented() +} diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt new file mode 100644 index 000000000..afe27c4a8 --- /dev/null +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt @@ -0,0 +1,34 @@ +package com.chuckerteam.chucker.api.dsl + +import com.chuckerteam.chucker.api.RetentionManager + +@DslMarker +annotation class ChuckerConfig + +@ChuckerConfig +fun configureChucker(config: ChuckerConfigBuilder.() -> Unit) = Unit + +@ChuckerConfig +class ChuckerConfigBuilder { + + @ChuckerConfig + fun http(block: HttpFeatureBuilder.() -> Unit) = Unit + + @ChuckerConfig + fun error(block: ErrorsFeatureBuilder.() -> Unit) = Unit + + fun build() = Unit +} + +@ChuckerConfig +class HttpFeatureBuilder { + var enabled: Boolean = true + var showNotification: Boolean = true + var retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK +} + +@ChuckerConfig +class ErrorsFeatureBuilder { + var enabled: Boolean = true + var showNotification: Boolean = true +} diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/internal/NoOp.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/internal/NoOp.kt new file mode 100644 index 000000000..d04e86a9c --- /dev/null +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/internal/NoOp.kt @@ -0,0 +1,5 @@ +package com.chuckerteam.chucker.internal + +internal fun notImplemented(): Nothing { + throw NotImplementedError() +} diff --git a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt index ddfb025db..ae1556175 100644 --- a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt +++ b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt @@ -20,4 +20,4 @@ class ChuckerApplication : Application() { } } } -} \ No newline at end of file +} From c49ec3a0b92cf0a8167e66798845181d3e53ae90 Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Tue, 15 Oct 2019 22:13:35 +0200 Subject: [PATCH 05/14] More help for Travis-CI --- .../main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/sample/src/main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt b/sample/src/main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt index a3a39c8de..b1730a9d0 100644 --- a/sample/src/main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt +++ b/sample/src/main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt @@ -4,7 +4,6 @@ import android.content.Context import com.chuckerteam.chucker.api.Chucker import com.chuckerteam.chucker.api.ChuckerCollector import com.chuckerteam.chucker.api.ChuckerInterceptor -import com.chuckerteam.chucker.api.RetentionManager import com.chuckerteam.chucker.sample.HttpBinApi.Data import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor From 25f86cb02e9de0989d286c8c6439dc159afd3a9c Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Thu, 24 Oct 2019 19:39:02 +0200 Subject: [PATCH 06/14] End of Kotlinizing README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 237a6a2d0..13c210ff2 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Chucker supports also collecting and displaying **Throwables** of your applicati ```kotlin try { // Do something risky -} catch (IOException exception) { +} catch (exception: IOException) { chuckerCollector.onError("TAG", exception) } ``` @@ -127,8 +127,8 @@ It is intended for **use during development**, and not in release builds or othe You can redact headers that contain sensitive information by calling `redactHeader(String)` on the `ChuckerInterceptor`. ```kotlin -interceptor.redactHeader("Auth-Token"); -interceptor.redactHeader("User-Session"); +interceptor.redactHeader("Auth-Token") +interceptor.redactHeader("User-Session") ``` ## Migrating 🚗 From 95a5de99e39b39e052537dd65fcafe81a0cf1f0b Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Thu, 24 Oct 2019 20:03:19 +0200 Subject: [PATCH 07/14] Add more stuff to DSL - maxContentLength - headersToRedact --- .../chucker/api/ChuckerInterceptor.kt | 31 +++++++------------ .../chucker/api/config/HttpFeature.kt | 4 ++- .../chucker/api/dsl/Configuration.dsl.kt | 23 +++++++++++++- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt index a2fa3e62a..9c2410aae 100755 --- a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt @@ -8,16 +8,16 @@ import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.support.FeatureManager import com.chuckerteam.chucker.internal.support.IOUtils import com.chuckerteam.chucker.internal.support.hasBody -import java.io.IOException -import java.nio.charset.Charset -import java.nio.charset.UnsupportedCharsetException -import java.util.concurrent.TimeUnit import okhttp3.Headers import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response import okio.Buffer import okio.BufferedSource +import java.io.IOException +import java.nio.charset.Charset +import java.nio.charset.UnsupportedCharsetException +import java.util.concurrent.TimeUnit private const val MAX_BLOB_SIZE = 1000_000L @@ -27,24 +27,17 @@ private const val MAX_BLOB_SIZE = 1000_000L * * @param context An Android [Context] * @param collector A [ChuckerCollector] to customize data retention - * @param maxContentLength The maximum length for request and response content - * before they are truncated. Warning: setting this value too high may cause unexpected - * results. - * @param headersToRedact List of headers that you want to redact. They will be not be shown in - * the ChuckerUI but will be replaced with a `**`. */ class ChuckerInterceptor @JvmOverloads constructor( private val context: Context, - private val collector: ChuckerCollector = ChuckerCollector(context), - private val maxContentLength: Long = 250000L, - private val headersToRedact: MutableSet = mutableSetOf() + private val collector: ChuckerCollector = ChuckerCollector(context) ) : Interceptor { private val io: IOUtils = IOUtils(context) private val httpFeature: HttpFeature = FeatureManager.find() fun redactHeader(name: String) = apply { - headersToRedact.add(name) + httpFeature.headersToRedact.add(name) } @Throws(IOException::class) @@ -142,7 +135,7 @@ class ChuckerInterceptor @JvmOverloads constructor( charset = contentType.charset(UTF8) ?: UTF8 } if (io.isPlaintext(buffer)) { - val content = io.readFromBuffer(buffer, charset, maxContentLength) + val content = io.readFromBuffer(buffer, charset, httpFeature.maxContentLength) transaction.requestBody = content } else { transaction.isResponseBodyPlainText = false @@ -151,11 +144,11 @@ class ChuckerInterceptor @JvmOverloads constructor( return transaction } - /** Overrides all the headers in [headersToRedact] with a `**` */ + /** Overrides all the headers in [HttpFeature.headersToRedact] with a `**` */ private fun filterHeaders(headers: Headers): Headers { val builder = headers.newBuilder() for (name in headers.names()) { - if (name in headersToRedact) { + if (name in httpFeature.headersToRedact) { builder.set(name, "**") } } @@ -168,8 +161,8 @@ class ChuckerInterceptor @JvmOverloads constructor( @Throws(IOException::class) private fun getNativeSource(response: Response): BufferedSource { if (io.bodyIsGzipped(response.headers().get("Content-Encoding"))) { - val source = response.peekBody(maxContentLength).source() - if (source.buffer().size() < maxContentLength) { + val source = response.peekBody(httpFeature.maxContentLength).source() + if (source.buffer().size() < httpFeature.maxContentLength) { return io.getNativeSource(source, true) } else { Log.w(LOG_TAG, "gzip encoded response was too long") @@ -180,7 +173,7 @@ class ChuckerInterceptor @JvmOverloads constructor( private fun HttpTransaction.completeWithBody(buffer: Buffer, charset: Charset) { if (io.isPlaintext(buffer)) { - val content = io.readFromBuffer(buffer.clone(), charset, maxContentLength) + val content = io.readFromBuffer(buffer.clone(), charset, httpFeature.maxContentLength) this.responseBody = content } else { this.isResponseBodyPlainText = false diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index dd296ba3d..637164108 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -10,7 +10,9 @@ import com.chuckerteam.chucker.internal.ui.transaction.TransactionListFragment class HttpFeature( override val enabled: Boolean, val showNotification: Boolean, - val retentionPeriod: RetentionManager.Period + val retentionPeriod: RetentionManager.Period, + var maxContentLength: Long, + var headersToRedact: MutableSet ) : Feature { override val name: Int = R.string.chucker_tab_network diff --git a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt index 4db9f7a4f..1845ffca8 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt @@ -38,11 +38,32 @@ class ChuckerConfigBuilder { @ChuckerConfig class HttpFeatureBuilder { var enabled: Boolean = true + /** + * Control whether a notification is shown while HTTP activity is recorded. + * The default is true. + */ var showNotification: Boolean = true + + /** + * Set the retention period for HTTP transaction data captured by this collector. + * The default is one week. + */ var retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK + /** + * The maximum length for request and response content before they are truncated. + * Warning: setting this value too high may cause unexpected results. + */ + var maxContentLength: Long = 250000L + + /** + * List of headers that you want to redact. They will be not be shown in + * the ChuckerUI but will be replaced with a `**`. + */ + var headersToRedact: MutableSet = mutableSetOf() + fun build(): HttpFeature = - HttpFeature(enabled, showNotification, retentionPeriod) + HttpFeature(enabled, showNotification, retentionPeriod, maxContentLength, headersToRedact) } @ChuckerConfig From ce97034ac1ba1c7332cb24936eaf4c6cddf0d69a Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Thu, 24 Oct 2019 20:05:29 +0200 Subject: [PATCH 08/14] Update "Configuration" chapter with the DSL --- README.md | 36 +++++++------------ .../chucker/sample/HttpBinClient.kt | 3 +- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 13c210ff2..e1c7952f6 100644 --- a/README.md +++ b/README.md @@ -78,32 +78,22 @@ The main Chucker activity is launched in its own task, allowing it to be display ## Configure 🎨 -You can customize chucker providing an instance of a `ChuckerCollector`: +You can customize Chucker by calling the DSL `configureChucker`. +It may be used to disable one of the features (HTTP or Errors). ```kotlin -// Create the Collector -val chuckerCollector = ChuckerCollector( - context = this, - // Toggles visibility of the push notification - showNotification = true, - // Allows to customize the retention period of collected data +configureChucker { + http { + enabled = true + showNotification = true retentionPeriod = RetentionManager.Period.ONE_HOUR -) - -// Create the Interceptor -val chuckerInterceptor = ChuckerInterceptor( - context = this, - // The previously created Collector - collector = chuckerCollector, - // The max body content length, after this responses will be truncated. - maxContentLength = 250000L, - // List of headers to obfuscate in the Chucker UI - headersToRedact = listOf("Auth-Token")) - -// Don't forget to plug the ChuckerInterceptor inside the OkHttpClient -val client = OkHttpClient.Builder() - .addInterceptor(chuckerInterceptor) - .build() + maxContentLength = 250000L + headersToRedact = listOf("Auth-Token") + } + error { + enabled = true + } +} ``` ### Throwables ☄️ diff --git a/sample/src/main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt b/sample/src/main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt index b1730a9d0..4ff04a904 100644 --- a/sample/src/main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt +++ b/sample/src/main/java/com/chuckerteam/chucker/sample/HttpBinClient.kt @@ -25,8 +25,7 @@ class HttpBinClient( private val chuckerInterceptor = ChuckerInterceptor( context = context, - collector = collector, - maxContentLength = 250000L + collector = collector ) private val httpClient = From ec9c9fed89371e4f5b2f46fb268b34abeebe9d7a Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Sat, 26 Oct 2019 14:44:19 +0200 Subject: [PATCH 09/14] Fix tag of HttpFeature --- .../main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index 637164108..e83db68ed 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -16,7 +16,7 @@ class HttpFeature( ) : Feature { override val name: Int = R.string.chucker_tab_network - override val tag: Int = Chucker.SCREEN_ERROR + override val tag: Int = Chucker.SCREEN_HTTP override fun newFragment(): Fragment { return TransactionListFragment.newInstance() From b8ba6485d33eec63ba6578c486d6cab22d36b451 Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Sat, 2 Nov 2019 04:48:25 +0100 Subject: [PATCH 10/14] Fix after Code review --- build.gradle | 1 + library-no-op/build.gradle | 1 + .../chucker/api/config/ErrorsFeature.kt | 12 ++++++------ .../chuckerteam/chucker/api/config/HttpFeature.kt | 12 ++++++------ .../api/config/{Feature.kt => TabFeature.kt} | 7 ++++--- .../chucker/api/dsl/Configuration.dsl.kt | 4 ++++ .../chucker/api/internal/EmptyFragment.kt | 5 +++++ .../java/com/chuckerteam/chucker/internal/NoOp.kt | 5 ----- .../chuckerteam/chucker/api/ChuckerInterceptor.kt | 8 ++++---- .../chucker/api/config/ErrorsFeature.kt | 4 ++-- .../chuckerteam/chucker/api/config/HttpFeature.kt | 4 ++-- .../api/config/{Feature.kt => TabFeature.kt} | 4 ++-- .../chucker/api/dsl/Configuration.dsl.kt | 4 +++- .../chucker/internal/support/FeatureManager.kt | 14 +++++++------- .../chucker/sample/ChuckerApplication.kt | 3 +++ 15 files changed, 50 insertions(+), 38 deletions(-) rename library-no-op/src/main/java/com/chuckerteam/chucker/api/config/{Feature.kt => TabFeature.kt} (60%) create mode 100644 library-no-op/src/main/java/com/chuckerteam/chucker/api/internal/EmptyFragment.kt delete mode 100644 library-no-op/src/main/java/com/chuckerteam/chucker/internal/NoOp.kt rename library/src/main/java/com/chuckerteam/chucker/api/config/{Feature.kt => TabFeature.kt} (88%) diff --git a/build.gradle b/build.gradle index 43c6415bf..6833a4966 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,7 @@ buildscript { retrofitVersion = '2.5.0' roomVersion = '2.1.0' supportLibVersion = '1.1.0-rc01' + fragmentVersion = '1.1.0' } repositories { diff --git a/library-no-op/build.gradle b/library-no-op/build.gradle index 9c27ef164..e84c5159a 100644 --- a/library-no-op/build.gradle +++ b/library-no-op/build.gradle @@ -21,6 +21,7 @@ artifacts { dependencies { implementation "com.squareup.okhttp3:okhttp:$okhttp3Version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation "androidx.fragment:fragment:$fragmentVersion" } apply from: rootProject.file('gradle/gradle-mvn-push.gradle') diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt index 7687f4ce5..4a287acf7 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt @@ -1,17 +1,17 @@ package com.chuckerteam.chucker.api.config import android.content.Context -import com.chuckerteam.chucker.internal.notImplemented +import com.chuckerteam.chucker.api.internal.EmptyFragment class ErrorsFeature( override val enabled: Boolean, val showNotification: Boolean -) : Feature { - override val name: Int = notImplemented() +) : TabFeature { + override val name: Int = 0 - override val tag: Int = notImplemented() + override val id: Int = 0 - override fun newFragment() = notImplemented() + override fun newFragment() = EmptyFragment() - override fun dismissNotification(context: Context) = notImplemented() + override fun dismissNotification(context: Context) {} } diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index 2392f9b73..e332136f0 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -2,18 +2,18 @@ package com.chuckerteam.chucker.api.config import android.content.Context import com.chuckerteam.chucker.api.RetentionManager -import com.chuckerteam.chucker.internal.notImplemented +import com.chuckerteam.chucker.api.internal.EmptyFragment class HttpFeature( override val enabled: Boolean, val showNotification: Boolean, val retentionPeriod: RetentionManager.Period -) : Feature { - override val name: Int = notImplemented() +) : TabFeature { + override val name: Int = 0 - override val tag: Int = notImplemented() + override val id: Int = 0 - override fun newFragment() = notImplemented() + override fun newFragment() = EmptyFragment() - override fun dismissNotification(context: Context) = notImplemented() + override fun dismissNotification(context: Context) {} } diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt similarity index 60% rename from library-no-op/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt rename to library-no-op/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt index 378e99f3c..fcc9ffc58 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt @@ -1,11 +1,12 @@ package com.chuckerteam.chucker.api.config import android.content.Context +import androidx.fragment.app.Fragment -interface Feature { +interface TabFeature { val name: Int - val tag: Int + val id: Int val enabled: Boolean - fun newFragment(): Nothing + fun newFragment(): Fragment fun dismissNotification(context: Context) } diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt index afe27c4a8..5030f6e38 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt @@ -2,6 +2,8 @@ package com.chuckerteam.chucker.api.dsl import com.chuckerteam.chucker.api.RetentionManager +const val DEFAULT_MAX_CONTENT_LENGTH = 250000L + @DslMarker annotation class ChuckerConfig @@ -25,6 +27,8 @@ class HttpFeatureBuilder { var enabled: Boolean = true var showNotification: Boolean = true var retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK + var maxContentLength: Long = 0 + var headersToRedact: MutableSet = mutableSetOf() } @ChuckerConfig diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/internal/EmptyFragment.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/internal/EmptyFragment.kt new file mode 100644 index 000000000..78f1eeb87 --- /dev/null +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/internal/EmptyFragment.kt @@ -0,0 +1,5 @@ +package com.chuckerteam.chucker.api.internal + +import androidx.fragment.app.Fragment + +class EmptyFragment : Fragment() diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/internal/NoOp.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/internal/NoOp.kt deleted file mode 100644 index d04e86a9c..000000000 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/internal/NoOp.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.chuckerteam.chucker.internal - -internal fun notImplemented(): Nothing { - throw NotImplementedError() -} diff --git a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt index 9c2410aae..cbc54847b 100755 --- a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt @@ -8,16 +8,16 @@ import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.support.FeatureManager import com.chuckerteam.chucker.internal.support.IOUtils import com.chuckerteam.chucker.internal.support.hasBody +import java.io.IOException +import java.nio.charset.Charset +import java.nio.charset.UnsupportedCharsetException +import java.util.concurrent.TimeUnit import okhttp3.Headers import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response import okio.Buffer import okio.BufferedSource -import java.io.IOException -import java.nio.charset.Charset -import java.nio.charset.UnsupportedCharsetException -import java.util.concurrent.TimeUnit private const val MAX_BLOB_SIZE = 1000_000L diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt index 3404d102e..1537e4ce4 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt @@ -9,10 +9,10 @@ import com.chuckerteam.chucker.internal.ui.error.ErrorListFragment class ErrorsFeature( override val enabled: Boolean, val showNotification: Boolean -) : Feature { +) : TabFeature { override val name: Int = R.string.chucker_tab_errors - override val tag: Int = Chucker.SCREEN_ERROR + override val id: Int = Chucker.SCREEN_ERROR override fun newFragment(): Fragment { return ErrorListFragment.newInstance() diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index e83db68ed..01c99db4a 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -13,10 +13,10 @@ class HttpFeature( val retentionPeriod: RetentionManager.Period, var maxContentLength: Long, var headersToRedact: MutableSet -) : Feature { +) : TabFeature { override val name: Int = R.string.chucker_tab_network - override val tag: Int = Chucker.SCREEN_HTTP + override val id: Int = Chucker.SCREEN_HTTP override fun newFragment(): Fragment { return TransactionListFragment.newInstance() diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt similarity index 88% rename from library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt rename to library/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt index ee427c682..f7ead760b 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/Feature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt @@ -4,10 +4,10 @@ import android.content.Context import androidx.annotation.StringRes import androidx.fragment.app.Fragment -interface Feature { +interface TabFeature { @get:StringRes val name: Int - val tag: Int + val id: Int val enabled: Boolean fun newFragment(): Fragment fun dismissNotification(context: Context) diff --git a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt index 1845ffca8..c1c89aba2 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt @@ -5,6 +5,8 @@ import com.chuckerteam.chucker.api.config.ErrorsFeature import com.chuckerteam.chucker.api.config.HttpFeature import com.chuckerteam.chucker.internal.support.FeatureManager +const val DEFAULT_MAX_CONTENT_LENGTH = 250000L + @DslMarker annotation class ChuckerConfig @@ -54,7 +56,7 @@ class HttpFeatureBuilder { * The maximum length for request and response content before they are truncated. * Warning: setting this value too high may cause unexpected results. */ - var maxContentLength: Long = 250000L + var maxContentLength: Long = DEFAULT_MAX_CONTENT_LENGTH /** * List of headers that you want to redact. They will be not be shown in diff --git a/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt b/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt index 54b642add..9f0b6cd6f 100644 --- a/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt +++ b/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt @@ -1,16 +1,16 @@ package com.chuckerteam.chucker.internal.support -import com.chuckerteam.chucker.api.config.Feature +import com.chuckerteam.chucker.api.config.TabFeature internal object FeatureManager { - private val features = mutableListOf() + private val features = mutableListOf() - fun configure(feature: Feature) { - features.add(feature) + fun configure(tabFeature: TabFeature) { + features.add(tabFeature) } - inline fun find(): T { + inline fun find(): T { return features.first { it is T } as T } @@ -18,11 +18,11 @@ internal object FeatureManager { return features.count { it.enabled } } - fun getAt(position: Int): Feature { + fun getAt(position: Int): TabFeature { return features.filter { it.enabled }[position] } fun getPositionOf(screenToShow: Int): Int { - return features.filter { it.enabled }.indexOfFirst { it.tag == screenToShow } + return features.filter { it.enabled }.indexOfFirst { it.id == screenToShow } } } diff --git a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt index ae1556175..9e4703778 100644 --- a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt +++ b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt @@ -2,6 +2,7 @@ package com.chuckerteam.chucker.sample import android.app.Application import com.chuckerteam.chucker.api.RetentionManager +import com.chuckerteam.chucker.api.dsl.DEFAULT_MAX_CONTENT_LENGTH import com.chuckerteam.chucker.api.dsl.configureChucker class ChuckerApplication : Application() { @@ -14,6 +15,8 @@ class ChuckerApplication : Application() { enabled = true showNotification = true retentionPeriod = RetentionManager.Period.ONE_HOUR + maxContentLength = DEFAULT_MAX_CONTENT_LENGTH + headersToRedact = mutableSetOf("Authorization", "Auth-Token", "User-Session") } error { enabled = true From 0a5cefe545b8c7558ca0cf6da3e7d60a0d5e8748 Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Sun, 3 Nov 2019 18:57:56 +0100 Subject: [PATCH 11/14] Avoid a big breaking change on ChuckerCollector and ChuckerInterceptor --- .../chucker/api/ChuckerCollector.kt | 12 ++++++++---- .../chucker/api/ChuckerInterceptor.kt | 12 +++++++++--- .../chucker/api/RetentionManager.kt | 5 ++--- .../chucker/api/config/ErrorsFeature.kt | 8 +++++--- .../chucker/api/config/HttpFeature.kt | 10 ++++++---- .../chucker/api/config/TabFeature.kt | 2 +- .../chucker/api/ChuckerCollector.kt | 14 ++++++++++++++ .../chucker/api/ChuckerInterceptor.kt | 15 ++++++++++++++- .../chucker/api/config/ErrorsFeature.kt | 12 ++++++++++-- .../chucker/api/config/HttpFeature.kt | 18 +++++++++++++++--- .../chucker/api/config/TabFeature.kt | 2 +- .../chucker/internal/support/FeatureManager.kt | 10 ++++++++-- .../chucker/internal/ui/HomePageAdapter.kt | 6 +----- .../chucker/sample/ChuckerApplication.kt | 1 + 14 files changed, 95 insertions(+), 32 deletions(-) diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt index 19b4c80bb..5fbaa1f39 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt @@ -5,11 +5,15 @@ import android.content.Context /** * No-op implementation. */ -class ChuckerCollector @JvmOverloads constructor( - context: Context, - var showNotification: Boolean = true, - var retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK +class ChuckerCollector( + context: Context ) { + @Deprecated("This constructor will disappear in a following version.") + constructor( + context: Context, + showNotification: Boolean, + retentionPeriod: RetentionManager.Period + ) : this(context) fun onError(obj: Any?, obj2: Any?) { // Empty method for the library-no-op artifact diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt index 537691a64..905fada57 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt @@ -10,11 +10,17 @@ import okhttp3.Response */ class ChuckerInterceptor @JvmOverloads constructor( context: Context, - collector: Any? = null, - maxContentLength: Any? = null, - headersToRedact: Any? = null + collector: Any? = null ) : Interceptor { + @Deprecated("This constructor will disappear in a following version.") + constructor( + context: Context, + collector: Any? = null, + maxContentLength: Any? = null, + headersToRedact: Any? = null + ) : this(context, collector) + fun redactHeaders(vararg names: String): ChuckerInterceptor { return this } diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/RetentionManager.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/RetentionManager.kt index c105fde10..74bdd5310 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/RetentionManager.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/RetentionManager.kt @@ -5,9 +5,8 @@ import android.content.Context /** * No-op implementation. */ -class RetentionManager @JvmOverloads constructor( - context: Context, - retentionPeriod: Any? = null +class RetentionManager( + context: Context ) { @Synchronized diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt index 4a287acf7..46e67fc6e 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt @@ -4,8 +4,8 @@ import android.content.Context import com.chuckerteam.chucker.api.internal.EmptyFragment class ErrorsFeature( - override val enabled: Boolean, - val showNotification: Boolean + override var enabled: Boolean, + var showNotification: Boolean ) : TabFeature { override val name: Int = 0 @@ -13,5 +13,7 @@ class ErrorsFeature( override fun newFragment() = EmptyFragment() - override fun dismissNotification(context: Context) {} + override fun dismissNotification(context: Context) { + // Empty method for the library-no-op artifact + } } diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index e332136f0..ca2fd3f8f 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -5,9 +5,9 @@ import com.chuckerteam.chucker.api.RetentionManager import com.chuckerteam.chucker.api.internal.EmptyFragment class HttpFeature( - override val enabled: Boolean, - val showNotification: Boolean, - val retentionPeriod: RetentionManager.Period + override var enabled: Boolean, + var showNotification: Boolean, + var retentionPeriod: RetentionManager.Period ) : TabFeature { override val name: Int = 0 @@ -15,5 +15,7 @@ class HttpFeature( override fun newFragment() = EmptyFragment() - override fun dismissNotification(context: Context) {} + override fun dismissNotification(context: Context) { + // Empty method for the library-no-op artifact + } } diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt index fcc9ffc58..9e9f6af9c 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt @@ -6,7 +6,7 @@ import androidx.fragment.app.Fragment interface TabFeature { val name: Int val id: Int - val enabled: Boolean + var enabled: Boolean fun newFragment(): Fragment fun dismissNotification(context: Context) } diff --git a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt index c177f8606..4892a7b81 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerCollector.kt @@ -19,8 +19,22 @@ import com.chuckerteam.chucker.internal.support.NotificationHelper class ChuckerCollector( context: Context ) { + @Deprecated("This constructor will disappear in a following version.") + constructor( + context: Context, + showNotification: Boolean, + retentionPeriod: RetentionManager.Period + ) : this(context) { + // This 3 lines are here to avoid breaking changes in the constructor signature + // They will disappear when we will make the breaking changes. + httpFeature.showNotification = showNotification + httpFeature.retentionPeriod = retentionPeriod + errorsFeature.showNotification = showNotification + } + private val retentionManager: RetentionManager = RetentionManager(context) private val notificationHelper: NotificationHelper = NotificationHelper(context) + private val httpFeature: HttpFeature = FeatureManager.find() private val errorsFeature: ErrorsFeature = FeatureManager.find() diff --git a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt index cbc54847b..548df8332 100755 --- a/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/ChuckerInterceptor.kt @@ -4,6 +4,7 @@ import android.content.Context import android.util.Log import com.chuckerteam.chucker.api.Chucker.LOG_TAG import com.chuckerteam.chucker.api.config.HttpFeature +import com.chuckerteam.chucker.api.dsl.DEFAULT_MAX_CONTENT_LENGTH import com.chuckerteam.chucker.internal.data.entity.HttpTransaction import com.chuckerteam.chucker.internal.support.FeatureManager import com.chuckerteam.chucker.internal.support.IOUtils @@ -33,6 +34,19 @@ class ChuckerInterceptor @JvmOverloads constructor( private val collector: ChuckerCollector = ChuckerCollector(context) ) : Interceptor { + @Deprecated("This constructor will disappear in a following version.") + constructor( + context: Context, + collector: ChuckerCollector = ChuckerCollector(context), + maxContentLength: Long = DEFAULT_MAX_CONTENT_LENGTH, + headersToRedact: MutableSet = mutableSetOf() + ) : this(context, collector) { + // This 2 lines are here to avoid breaking changes in the constructor signature + // They will disappear when we will make the breaking changes. + httpFeature.maxContentLength = maxContentLength + httpFeature.headersToRedact = headersToRedact + } + private val io: IOUtils = IOUtils(context) private val httpFeature: HttpFeature = FeatureManager.find() @@ -41,7 +55,6 @@ class ChuckerInterceptor @JvmOverloads constructor( } @Throws(IOException::class) - @Suppress("LongMethod", "ComplexMethod") override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt index 1537e4ce4..7132aa95b 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/ErrorsFeature.kt @@ -7,8 +7,8 @@ import com.chuckerteam.chucker.api.Chucker import com.chuckerteam.chucker.internal.ui.error.ErrorListFragment class ErrorsFeature( - override val enabled: Boolean, - val showNotification: Boolean + override var enabled: Boolean, + var showNotification: Boolean ) : TabFeature { override val name: Int = R.string.chucker_tab_errors @@ -21,4 +21,12 @@ class ErrorsFeature( override fun dismissNotification(context: Context) { Chucker.dismissErrorsNotification(context) } + + companion object { + fun default(): ErrorsFeature = + ErrorsFeature( + enabled = true, + showNotification = true + ) + } } diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index 01c99db4a..59cd812e4 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -5,12 +5,13 @@ import androidx.fragment.app.Fragment import com.chuckerteam.chucker.R import com.chuckerteam.chucker.api.Chucker import com.chuckerteam.chucker.api.RetentionManager +import com.chuckerteam.chucker.api.dsl.DEFAULT_MAX_CONTENT_LENGTH import com.chuckerteam.chucker.internal.ui.transaction.TransactionListFragment class HttpFeature( - override val enabled: Boolean, - val showNotification: Boolean, - val retentionPeriod: RetentionManager.Period, + override var enabled: Boolean, + var showNotification: Boolean, + var retentionPeriod: RetentionManager.Period, var maxContentLength: Long, var headersToRedact: MutableSet ) : TabFeature { @@ -25,4 +26,15 @@ class HttpFeature( override fun dismissNotification(context: Context) { Chucker.dismissTransactionsNotification(context) } + + companion object { + fun default(): HttpFeature = + HttpFeature( + enabled = true, + showNotification = true, + retentionPeriod = RetentionManager.Period.ONE_WEEK, + headersToRedact = mutableSetOf(), + maxContentLength = DEFAULT_MAX_CONTENT_LENGTH + ) + } } diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt index f7ead760b..57f9025f7 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/TabFeature.kt @@ -8,7 +8,7 @@ interface TabFeature { @get:StringRes val name: Int val id: Int - val enabled: Boolean + var enabled: Boolean fun newFragment(): Fragment fun dismissNotification(context: Context) } diff --git a/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt b/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt index 9f0b6cd6f..7e858beeb 100644 --- a/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt +++ b/library/src/main/java/com/chuckerteam/chucker/internal/support/FeatureManager.kt @@ -1,17 +1,23 @@ package com.chuckerteam.chucker.internal.support +import com.chuckerteam.chucker.api.config.ErrorsFeature +import com.chuckerteam.chucker.api.config.HttpFeature import com.chuckerteam.chucker.api.config.TabFeature internal object FeatureManager { - private val features = mutableListOf() + private val features: MutableList = mutableListOf( + HttpFeature.default(), + ErrorsFeature.default() + ) fun configure(tabFeature: TabFeature) { + features.removeAll { it.javaClass == tabFeature.javaClass } features.add(tabFeature) } inline fun find(): T { - return features.first { it is T } as T + return features.firstOrNull { it is T } as T } fun countEnabledFeatures(): Int { diff --git a/library/src/main/java/com/chuckerteam/chucker/internal/ui/HomePageAdapter.kt b/library/src/main/java/com/chuckerteam/chucker/internal/ui/HomePageAdapter.kt index 00b39d507..41bc0a6e7 100644 --- a/library/src/main/java/com/chuckerteam/chucker/internal/ui/HomePageAdapter.kt +++ b/library/src/main/java/com/chuckerteam/chucker/internal/ui/HomePageAdapter.kt @@ -9,6 +9,7 @@ import java.lang.ref.WeakReference internal class HomePageAdapter(context: Context, fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + private val context: WeakReference = WeakReference(context) override fun getItem(position: Int): Fragment = @@ -18,9 +19,4 @@ internal class HomePageAdapter(context: Context, fragmentManager: FragmentManage override fun getPageTitle(position: Int): CharSequence? = context.get()?.getString(FeatureManager.getAt(position).name) - - companion object { - const val SCREEN_HTTP_INDEX = 0 - const val SCREEN_ERROR_INDEX = 1 - } } diff --git a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt index 9e4703778..0d4793474 100644 --- a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt +++ b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt @@ -20,6 +20,7 @@ class ChuckerApplication : Application() { } error { enabled = true + showNotification = true } } } From cd4155ea1bf323ac7b01f296f7d7f5c079d52c29 Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Mon, 4 Nov 2019 21:27:30 +0100 Subject: [PATCH 12/14] Add a way to configure Chucker for Java developers --- .../chucker/api/config/ChuckerJavaConfig.kt | 7 +++ .../chucker/api/config/HttpFeature.kt | 4 +- .../chucker/api/config/ChuckerJavaConfig.kt | 9 ++++ .../sample/ChuckerJavaApplication.java | 43 +++++++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ChuckerJavaConfig.kt create mode 100644 library/src/main/java/com/chuckerteam/chucker/api/config/ChuckerJavaConfig.kt create mode 100644 sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerJavaApplication.java diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ChuckerJavaConfig.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ChuckerJavaConfig.kt new file mode 100644 index 000000000..e4ef28ca4 --- /dev/null +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/ChuckerJavaConfig.kt @@ -0,0 +1,7 @@ +@file:JvmName("ChuckerJavaConfig") + +package com.chuckerteam.chucker.api.config + +fun configure(features: List) { + // Empty method for the library-no-op artifact +} diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt index ca2fd3f8f..b7ed57791 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/config/HttpFeature.kt @@ -7,7 +7,9 @@ import com.chuckerteam.chucker.api.internal.EmptyFragment class HttpFeature( override var enabled: Boolean, var showNotification: Boolean, - var retentionPeriod: RetentionManager.Period + var retentionPeriod: RetentionManager.Period, + var maxContentLength: Long, + var headersToRedact: MutableSet ) : TabFeature { override val name: Int = 0 diff --git a/library/src/main/java/com/chuckerteam/chucker/api/config/ChuckerJavaConfig.kt b/library/src/main/java/com/chuckerteam/chucker/api/config/ChuckerJavaConfig.kt new file mode 100644 index 000000000..f72b30377 --- /dev/null +++ b/library/src/main/java/com/chuckerteam/chucker/api/config/ChuckerJavaConfig.kt @@ -0,0 +1,9 @@ +@file:JvmName("ChuckerJavaConfig") + +package com.chuckerteam.chucker.api.config + +import com.chuckerteam.chucker.internal.support.FeatureManager + +fun configure(features: List) { + features.forEach(FeatureManager::configure) +} diff --git a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerJavaApplication.java b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerJavaApplication.java new file mode 100644 index 000000000..d18f936b1 --- /dev/null +++ b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerJavaApplication.java @@ -0,0 +1,43 @@ +package com.chuckerteam.chucker.sample; + +import android.app.Application; + +import com.chuckerteam.chucker.api.RetentionManager; +import com.chuckerteam.chucker.api.config.ChuckerJavaConfig; +import com.chuckerteam.chucker.api.config.ErrorsFeature; +import com.chuckerteam.chucker.api.config.HttpFeature; +import com.chuckerteam.chucker.api.config.TabFeature; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import static com.chuckerteam.chucker.api.dsl.Configuration_dslKt.DEFAULT_MAX_CONTENT_LENGTH; + +public class ChuckerJavaApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + HashSet headersToRedact = new HashSet<>(); + headersToRedact.add("Authorization"); + headersToRedact.add("Auth-Token"); + headersToRedact.add("User-Session"); + + List features = Arrays.asList( + new HttpFeature( + true, + true, + RetentionManager.Period.ONE_HOUR, + DEFAULT_MAX_CONTENT_LENGTH, + headersToRedact + ), + new ErrorsFeature( + true, + true + ) + ); + + ChuckerJavaConfig.configure(features); + } +} From cf1300dc1de9c01931dabd4524a4584a007d3d14 Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Mon, 4 Nov 2019 21:41:22 +0100 Subject: [PATCH 13/14] Change way to redact headers in Kotlin DSL --- .../chucker/api/dsl/Configuration.dsl.kt | 11 ++++++++++- .../chucker/api/dsl/Configuration.dsl.kt | 15 ++++++++++++++- .../chucker/sample/ChuckerApplication.kt | 6 +++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt b/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt index 5030f6e38..38aa33e00 100644 --- a/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt +++ b/library-no-op/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt @@ -28,7 +28,16 @@ class HttpFeatureBuilder { var showNotification: Boolean = true var retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_WEEK var maxContentLength: Long = 0 - var headersToRedact: MutableSet = mutableSetOf() + internal var headersToRedact: MutableSet = mutableSetOf() + + @ChuckerConfig + fun headers(redactHeaders: RedactHeaders.() -> Unit) = Unit +} + +@ChuckerConfig +class RedactHeaders { + @ChuckerConfig + fun redact(header: String) = Unit } @ChuckerConfig diff --git a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt index c1c89aba2..3524eb6af 100644 --- a/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt +++ b/library/src/main/java/com/chuckerteam/chucker/api/dsl/Configuration.dsl.kt @@ -62,10 +62,23 @@ class HttpFeatureBuilder { * List of headers that you want to redact. They will be not be shown in * the ChuckerUI but will be replaced with a `**`. */ - var headersToRedact: MutableSet = mutableSetOf() + internal var headersToRedact: MutableSet = mutableSetOf() fun build(): HttpFeature = HttpFeature(enabled, showNotification, retentionPeriod, maxContentLength, headersToRedact) + + @ChuckerConfig + fun headers(redactHeaders: RedactHeaders.() -> Unit) { + RedactHeaders(this).apply(redactHeaders) + } +} + +@ChuckerConfig +class RedactHeaders(private val httpFeature: HttpFeatureBuilder) { + @ChuckerConfig + fun redact(header: String) { + httpFeature.headersToRedact.add(header) + } } @ChuckerConfig diff --git a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt index 0d4793474..4fc52cc9d 100644 --- a/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt +++ b/sample/src/main/java/com/chuckerteam/chucker/sample/ChuckerApplication.kt @@ -16,7 +16,11 @@ class ChuckerApplication : Application() { showNotification = true retentionPeriod = RetentionManager.Period.ONE_HOUR maxContentLength = DEFAULT_MAX_CONTENT_LENGTH - headersToRedact = mutableSetOf("Authorization", "Auth-Token", "User-Session") + headers { + redact("Authorization") + redact("Auth-Token") + redact("User-Session") + } } error { enabled = true From 4fe7207784f2357ec8aeff5cf1b1004fcae14f26 Mon Sep 17 00:00:00 2001 From: Olivier PEREZ Date: Mon, 4 Nov 2019 21:45:37 +0100 Subject: [PATCH 14/14] Update README in regard of last changes --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e1c7952f6..3d210d11a 100644 --- a/README.md +++ b/README.md @@ -88,14 +88,44 @@ configureChucker { showNotification = true retentionPeriod = RetentionManager.Period.ONE_HOUR maxContentLength = 250000L - headersToRedact = listOf("Auth-Token") + headers { + redact("Authorization") + redact("Auth-Token") + redact("User-Session") + } } error { enabled = true + showNotification = true } } ``` +### Configure for Java + +```java +HashSet headersToRedact = new HashSet<>(); +headersToRedact.add("Authorization"); +headersToRedact.add("Auth-Token"); +headersToRedact.add("User-Session"); + +List features = Arrays.asList( + new HttpFeature( + true, + true, + RetentionManager.Period.ONE_HOUR, + DEFAULT_MAX_CONTENT_LENGTH, + headersToRedact + ), + new ErrorsFeature( + true, + true + ) +); + +ChuckerJavaConfig.configure(features); +``` + ### Throwables ☄️ Chucker supports also collecting and displaying **Throwables** of your application. To inform Chucker that a `Throwable` was fired you need to call the `onError` method of the `ChuckerCollector` (you need to retain an instance of your collector):