Error Analysis
Prerequisites
Section titled PrerequisitesScreen tracking implemented
Section titled Screen tracking implementedTracking will start at the 1st screenview event, it is required to have screen tracking implemented. Make sure to follow the Android Track screens sections.
Reminder about User consent
Section titled Reminder about User consentIf you are in the process of implementing the SDK for the 1st time (or choose to take this update as an opportunity to review your Privacy related implementation), make sure to follow the Android Privacy sections.
API errors
Section titled API errorsAutomatic network inspection
Section titled Automatic network inspectionBy using code instrumentation, network calls will be instrumented to collect network data.
This way, two largely used network stacks are supported, and all the libraries that use them:
Adding the Gradle plugin
Section titled Adding the Gradle pluginWith the use of a Gradle plugin, an instrumentation of your code will be performed to collect the data about network errors.
In your root-level (project-level) Gradle file (<project>/build.gradle
or <project>/build.gradle.kts
), add the Contentsquare Network Gradle plugin to the plugins block:
Using the plugins DSL:
plugins { // Add the dependency for the Contentsquare Network Gradle plugin id "com.contentsquare.error.analysis.network" version "1.2.0" apply false}
Using legacy plugin application:
buildscript { repositories { maven { url "https://plugins.gradle.org/m2" } } dependencies { classpath "com.contentsquare.gradle:error-analysis-network:1.2.0" }}
Using the plugins DSL:
plugins { // Add the dependency for the Contentsquare Network Gradle plugin id("com.contentsquare.error.analysis.network") version "1.2.0" apply false}
Using legacy plugin application:
buildscript { repositories { maven { url = uri("https://plugins.gradle.org/m2") } } dependencies { classpath("com.contentsquare.gradle:error-analysis-network:1.2.0") }}
apply(plugin = "com.contentsquare.error.analysis.network")
In your module (app-level) Gradle file (usually <project>/<app-module>/build.gradle
or <project>/<app-module>/build.gradle.kts
), add the Contentsquare Network Gradle plugin:
Using the plugins DSL:
plugins { id "com.contentsquare.error.analysis.network"}
Using legacy plugin application:
apply plugin: "com.contentsquare.error.analysis.network"
Using the plugins DSL:
plugins { id("com.contentsquare.error.analysis.network")}
Using legacy plugin application:
apply(plugin = "com.contentsquare.error.analysis.network")
Task added
Section titled Task addedThe plugin adds new tasks for network code instrumentation: transformVariantClassesWithAsm
This task can be time consuming, and should be disabled for development build.
Configure Gradle plugin
Section titled Configure Gradle pluginBy default the plugin is enabled for each variant, there are three ways to disable the Gradle plugin:
Build type
Section titled Build typeandroid { buildTypes { debug { errorAnalysisNetwork { setInstrumentationEnabled(false) } } }}
android { buildTypes { debug { configure<com.contentsquare.gradle.error.analysis.network.ErrorAnalysisNetworkExtension> { setInstrumentationEnabled(false) } } }}
By flavor
Section titled By flavorandroid { flavorDimensions "example" productFlavors { enable { dimension "example" } disable { dimension "example" errorAnalysisNetwork { setInstrumentationEnabled(false) } } }}
android { flavorDimensions += "example" productFlavors { create("enable") { dimension = "example" } create("disable") { dimension = "example" configure<com.contentsquare.gradle.error.analysis.network.ErrorAnalysisNetworkExtension> { setInstrumentationEnabled(false) } } }}
With a Gradle properties
Section titled With a Gradle propertieserrorAnalysisNetworkInstrumentationEnabled=false
Command line:
./gradlew :app:assembleDebug -PerrorAnalysisNetworkInstrumentationEnabled=false
Manual inspection
Section titled Manual inspectionOkHttp interceptor
Section titled OkHttp interceptorIf your project is using OkHttp client, an interceptor (ErrorAnalysisInterceptor
) can be added to collect all the network errors:
import com.contentsquare.android.error.analysis.network.ErrorAnalysisInterceptor;
new OkHttpClient().newBuilder() .addInterceptor(new ErrorAnalysisInterceptor()) .build();
import com.contentsquare.android.error.analysis.network.ErrorAnalysisInterceptor
OkHttpClient().newBuilder() .addInterceptor(ErrorAnalysisInterceptor()) .build()
Custom implementation
Section titled Custom implementationIf no other solution works, a custom implementation can be created via the newNetworkMetric
method.
Multiple data will need to be gathered: URL and method at the creation of the metric, and status code after the request is done.
Also calling start
(before the request) and stop
(after all the rest) methods for time metrics to be collect and to send the event.
import com.contentsquare.android.error.analysis.ErrorAnalysis;import com.contentsquare.android.error.analysis.NetworkMetric;
NetworkMetric metric = ErrorAnalysis.getInstance().newNetworkMetric(url, ErrorAnalysis.HttpMethod.GET);metric.start();
// do your request
metric.setStatusCode(code);metric.stop();
import com.contentsquare.android.error.analysis.ErrorAnalysisimport com.contentsquare.android.error.analysis.trace
ErrorAnalysis.getInstance().newNetworkMetric(url, ErrorAnalysis.HttpMethod.GET).trace {
// do your request
setStatusCode(code)}
Removing Personal Data in request URL path
Section titled Removing Personal Data in request URL pathBy default, the API errors feature collects the URL path of the failed API requests. To prevent the collection of Personal Data in the URL path, you can rewrite the request URL path with the ErrorAnalysis.setUrlMaskingPatterns
SDK API.
Simply replace a step of the path - meaning between two slashes (/) - containing Personal Data with a variable:
:user_id
becomes CS_ANONYMIZED_USER_ID:address
becomes CS_ANONYMIZED_ADDRESS
Example
Section titled ExampleErrorAnalysis.setUrlMaskingPatterns( List.of("https://www.contentsquare.com/users/:user_id/address/:address"));
ErrorAnalysis.setUrlMaskingPatterns( listOf("https://www.contentsquare.com/users/:user_id/address/:address"))
Result
Section titled ResultURL before masking | URL after masking |
---|---|
https://www.contentsquare.com/users/123/address/castle+black | https://www.contentsquare.com/users/CS_ANONYMIZED_USER_ID/address/CS_ANONYMIZED_ADDRESS |
Validate API error integration
Section titled Validate API error integrationValidate API error collection is enabled
Section titled Validate API error collection is enabledIf in-app features are enabled, an info log should appear when API Error collection has successfully been enabled (see Android Debugging and Logging section).:
CSLIB: Api Error collection is enabled
Validate API error collection
Section titled Validate API error collectionIf you have logging enabled, you will see API errors:
- Displayed in Contentsquare Log Visualizer.
- As an Info log in Logcat:
CSLIB: API Error - 401 GET https://api.client.com
How API errors works
Section titled How API errors worksInitialization
Section titled InitializationThe way our SDK works is by auto-starting with the application launch and collects the API errors through the instrumented code added by the Gradle plugin.
Configuration
Section titled ConfigurationOnce started, our SDK fetches its config from our servers. It will start collecting data from network events if the API errors setting is enabled in the config (this is handled by the Contentsquare team).
API errors collection
Section titled API errors collectionThe SDK monitors only the API errors with response code equal or above 400, and generates analytics data. These events are then locally stored, and eventually sent to our servers in batches.
Sending API errors data
Section titled Sending API errors dataFor each network error, a new event will be sent in analytics and Session Replay data. Check the following sections to learn more about how data is processed and sent:
API Troubleshooting Details
Section titled API Troubleshooting DetailsAPI errors troubleshooting details enables you to collect more information about API errors so you can troubleshoot errors faster.
With this feature you will be able to see three types of additional API error details in the Event Stream of Session Replay.
- The HTTP headers of the request and the response.
- The body (the data sent by the request or received in the response).
- The query parameters of the request endpoint (of the URL of the information you request for).
See API Troubleshooting Details for more details.
Collected data points
Section titled Collected data pointsOnly network calls in error (response code above 400) will be collected.
Here the exhaustive list of data collected:
- Response code
- URL (without query strings)
- HTTP method
- Timestamp of the request
- Timestamp of the response
Known limitations and recommendations
Section titled Known limitations and recommendationsConflict with Firebase Performance using code instrumentation
Section titled Conflict with Firebase Performance using code instrumentationCode instrumentation does not work well with Firebase Performance plugin.
Network events will not be logged for OkHttp when using Contentsquare Error Analysis network and Firebase performance plugin (only one of the two will log events).
If you want to use both libraries, prefer using interceptors than code instrumentation.
Crash Reporter
Section titled Crash ReporterUpload mapping file
Section titled Upload mapping fileAndroid mapping files are generated during the process of obfuscating Android application code using tools like ProGuard. It will be generated for all obfuscated builds at compile time. Here is the Google description : Shrink, obfuscate, and optimize your app The purpose of obfuscation is to reduce the app size by shortening the names of the app’s classes, methods, and fields. The following is an example of mapping file for the Contentsquare Android sample app (see mapping.txt.zip)
In order to produce readable crash reports from builds that have been obfuscated, Contentsquare requires you to upload the mapping file produced by your build to our servers. To simplify this process, we’ve provided a Gradle plugin that you can integrate into your build. It adds a distinct Gradle task which should be executed once the build is done, ideally immediately to ensure that the mapping file has not been removed. See Perform Upload.
Adding the Gradle plugin
Section titled Adding the Gradle pluginIn your root-level (project-level) Gradle file (<project>/build.gradle
or <project>/build.gradle.kts
), add the Contentsquare Crash Gradle plugin to the plugins block:
Using the plugins DSL:
plugins { // Add the dependency for the Contentsquare Crash Gradle plugin id "com.contentsquare.error.analysis.crash" version "1.3.0" apply false}
Using legacy plugin application:
buildscript { repositories { maven { url "https://plugins.gradle.org/m2" } } dependencies { classpath "com.contentsquare.gradle:error-analysis-crash:1.3.0" }}
Using the plugins DSL:
plugins { // Add the dependency for the Contentsquare Crash Gradle plugin id("com.contentsquare.error.analysis.crash") version "1.3.0" apply false}
Using legacy plugin application:
buildscript { repositories { maven { url = uri("https://plugins.gradle.org/m2") } } dependencies { classpath("com.contentsquare.gradle:error-analysis-crash:1.3.0") }}
In your module (app-level) Gradle file (usually <project>/<app-module>/build.gradle
or <project>/<app-module>/build.gradle.kts
), add the Contentsquare Crash Gradle plugin:
Using the plugins DSL:
plugins { id "com.contentsquare.error.analysis.crash"}
Using legacy plugin application:
apply plugin: "com.contentsquare.error.analysis.crash"
Using the plugins DSL:
plugins { id("com.contentsquare.error.analysis.crash")}
Using legacy plugin application:
apply(plugin = "com.contentsquare.error.analysis.crash")
Configuring the Gradle Plugin
Section titled Configuring the Gradle PluginTo use the plugin, you must provide it with the relevant credentials to be able to upload the mapping file.
Get project ID
Section titled Get project ID- Login to the Contentsquare platform on https://app.contentsquare.com
- Make sure to be on the right project
- The project ID can be found in the URL query parameter
project
:https://app.contentsquare.com/#/{MODULE_NAME}?project={PROJECT_ID}&hash={HASH}
Get project credentials
Section titled Get project credentialsFollow the dedicated documentation from the Help Center to get the client ID and client Secret: How to create API credentials.
Use credentials
Section titled Use credentialsYou can do this by setting the uploadCredentials
property of the errorAnalysisCrash extension in your app-level build.gradle
or build.gradle.kts
file, as shown below. The errorAnalysisCrash extension is available on all build types and product flavours.
android { buildTypes { release { errorAnalysisCrash { uploadCredentials { projectId = <you project Id> clientId = "<your client Id>" clientSecret = "<your client secret>" } } } }}
android { buildTypes { release { configure<ErrorAnalysisCrashExtension> { uploadCredentials { projectId = <your project Id> clientId = "<your client Id>" clientSecret = "<your client secret>" } } } }}
ProGuard Configuration
Section titled ProGuard ConfigurationTo ensure that we can provide line numbers and file names in the crash reports, add the following configuration to your ProGuard file:
-keepattributes SourceFile,LineNumberTable # Keep file names and line numbers
Perform Upload
Section titled Perform UploadThe upload task is independent from any other tasks in build graph. Once your build is complete, and the mapping file has been generated, you can upload it follows:
./gradlew uploadContentsquareMappingFile<VariantName>
Replace <VariantName> with the name of the build variant you want to upload the mapping file for.
Integrate with a CI/CD pipeline
Section titled Integrate with a CI/CD pipelineWe strongly recommend to run this as a task in a CI/CD pipeline for the obfuscated builds.
Validate Crash reporter integration
Section titled Validate Crash reporter integrationValidate crash collection is activated
Section titled Validate crash collection is activatedIf in-app features are enabled, an info log should appear when the Crash reporter has successfully been initialized (see Android Debugging and Logging section).:
CSLIB: Crash reporter is enabled
Validate crash reporting
Section titled Validate crash reportingTo test that the Crash Reporter is working properly, you can force a crash in your application. The next time you start your application, the crash will be sent to our servers. If you have logging enabled, you will see the upload reflected in the log:
I/CSLIB: Crash event detected and sent for userID: <user-id>, session: <session-number> on screen: <screen-number> crashID: <crash-id>
How Crash Reporter works
Section titled How Crash Reporter worksInitialization
Section titled InitializationCrash Reporter is started automatically and begins to report basic information for crashes in your application when it is launched.
Configuration
Section titled ConfigurationOnce started, our SDK fetches its configuration from our servers. It will start reporting crashes if the Crash Reporter setting is enabled (this is handled by the Contentsquare team).
Reporting
Section titled ReportingWhen a crash occurs, a report is created and stored locally in the device. Once the app is launched again, the report is sent to our servers and then removed from the local storage.
Sending crash data
Section titled Sending crash dataFor each crash, a new event will be sent to Analytics and Session Replay data when the app is launched again after the crash occurred and the network conditions allow for the server to be reached.
Collected data points
Section titled Collected data pointsThe Crash Reporter will capture any crashes caused by an unhandled exception in applications written in Java or Kotlin. It will collect information about the application, system, process, threads, stack traces and some other event metadata you can find in collected data points
Known limitations and recommendations
Section titled Known limitations and recommendationsNative crashes from applications written using C or C++ are currently not supported.
Compatibility with other crash reporters
Section titled Compatibility with other crash reportersIt is possible that the Crash Reporter will work with other SDKs, but we cannot guarantee it. Android has a global error handling class and therefore we rely on other SDKs forwarding the error on to us in the event of a crash, should they have been registered first. If the Contentsquare Crash Reporter is registered first, it will forward on errors to any other registered handlers.
Based on our tests, we can confirm it is compatible with Firebase Crashlytics.
WebView errors
Section titled WebView errorsErrors occurring in web pages loaded in WebViews can be collected if Webview tracking is setup in your app.
See 📚 Webview Tracking implementation.
Once WebView tracking is implemented, errors collection can be set up.
See 📚 Errors (in WebView)
Compatibility
Section titled CompatibilityDependencies list
Section titled Dependencies listPackage | Name | Version |
---|---|---|
androidx.annotation | annotation | 1.5.0 |
Impact on Performance
Section titled Impact on PerformanceWe always strive to be non-intrusive, and transparent to the developers of the client app. We apply this rule on the performance as well. These are the technical specifics we can share on performance, if you have any questions feel free to reach out to us.
The following performance results were obtained under the following conditions:
Condition | Value |
---|---|
Device model | Pixel 5 |
Android version | 13 |
We used Android Microbenchmark to measure the time added by our implementation.
The instrumented code added is running in less than 1ms per request: our benchmarks show less 400µs.
About CPU and memory, the overhead of adding the collection of network error is negligible.
Migrating from versions 4.24.1 and older of Error Analysis
Section titled Migrating from versions 4.24.1 and older of Error AnalysisIn versions prior to 4.25.0 of the Contentsquare SDK, the Error Analysis module was provided as a distinct artifact. To integrate it into your application, a dedicated Gradle dependency was required. Starting from version 4.25.0, this is no longer the case.
If you had previously integrated the Error Analysis module into your application using the standalone artifact, you will need to remove it from your dependency list.
// Remove the following line from your dependenciesimplementation "com.contentsquare.android:error-analysis:4.24.1"
// Remove the following line from your dependenciesimplementation "com.contentsquare.android:error-analysis:4.24.1"
Should you fail to follow these steps you will see one of the following errors.
In the event of not removing the error-analysis module and upgrading the version, it will not be found:
FAILURE: Build failed with an exception.
* What went wrong:Execution failed for task ':app:dataBindingMergeDependencyArtifactsRelease'.> Could not resolve all files for configuration ':app:releaseCompileClasspath'. > Could not find com.contentsquare.android:error-analysis:4.25.0. Required by: project :app
In the event of not removing the error-analysis module and keeping it on version 4.24.0, you will see a list of duplicate classes found:
> Task :app:checkDebugDuplicateClasses FAILED
FAILURE: Build failed with an exception.
* What went wrong:Execution failed for task ':app:checkDebugDuplicateClasses'.> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable > Duplicate class com.contentsquare.android.ErrorAnalysisModule found...