Mobile App monitoring FAQ
Mobile App monitoring FAQ covers setup, troubleshooting, and best practices for effective monitoring of mobile applications.
Data collection and reporting
Which app data is collected?
Along with the Instana monitoring, the mobile agent automatically collects the following app-specific information:
- Bundle or App identifier
- App and build version
- Current app language
- iOS/Android version, device model, hardware, device, and manufacturer
- Whether a device is jailbroken or rooted
- Screen size and resolution
- Carrier name and connection type (
2G
,3G
,4G
...)
How is beacon reporting handled?
To avoid blocking the main thread (UI), reporting and queue handling is performed in a background thread.
The agent collects all incoming beacons in a persistent queue in the device, so beacons are not lost if unexpected eventualities like crashes or forceful shutdowns occur. Each beacon requires around 600 bytes of storage space.
Generation of beacons is rate-limited to 20 beacons in each 10-second slot, and 500 beacons in each 5-minute slot.
Beacons are flushed one second after the beacon generation stops (ten seconds if the battery is low) to prevent any impact on your app's network performance.
Before you flush, the beacons joined in batches of 100. Each batch is then transmitted in a single HTTP request (compressed if the device supports it, the same HTTP connection if the device supports it).
If the device is offline when the agent tries to send them, the agent waits until the device comes back online to send the beacons.
The queue has a default max limit of 1000 beacons. If more beacons are generated while the queue is full, new beacons are discarded.
If the transmission of beacons receives an error response from the server, the agent automatically retries the transmission up to 3 times by using a 10s exponential backoff mechanism. If this automatic retry fails, the beacons will still not be dropped, they stay in the queue to be retried together with the rest of the queue when new beacons are generated.
What happens for users with bad internet or network connections?
Data transmission requests from your mobile app users to our servers might not be working. In these cases, we attempt to deliver the beacons as part of the next monitoring data transmission, for example, on the following mobile app start.
What happens when reporting fails?
Due to network problems, beacon reporting can fail. The beacons are retained in the queue for the next transmission attempt.
Is data collected while offline?
Yes, consider the limit of 100 beacons that are described here. When the queue is full and cannot be flushed (due to network issues), all upcoming beacons are discarded.
Is it possible to proxy the HTTP endpoints (for SaaS)?
Instana recommends not to attempt the proxying of the HTTP endpoints. Instana does not provide any support for any proxy setups nor for any issues that can arise due to the usage of a proxy. If you still want (or have) to do this, you can find these pointers helpful:
- Set proper
Host
HTTP headers. - Respect the difference between the
eum.instana.io
andeum-{region}.instana.io
servers. - Make sure that our servers are aware of the users IPs. Send
X-FORWARDED-FOR
header to servers with the user's IP. Alternatively send aX-REALER-IP
HTTP header (yes, deliberately notX-REAL-IP
) to the Instana servers, which contains the user's IP. - Pass through all the HTTP headers that the Instana servers include in the response body.
- Don't do any caching in the proxy.
Can Instana monitoring be enabled in Android app debug build during the testing phase?
Currently, you can use Gradle to get conditional plug-in usage:
See the following examples in the instana-example
directory in the Instana repository:
instana-example/app/build.gradle
instana-example/app/src/main/java/com/instana/mobileeum/DemoApp.kt
- Instana provides two libraries for Android monitoring, the `plugin` library and the `runtime` library. The following steps are based on the build types as follows:
- Instana `plugin` library is not loaded at all.
- Instana `runtime` library is still packaged into your app bundle, however, it is left `uninitialized`.
If you don't want any of the Instana codes to be executed in your app, follow the steps:
-
Get the current BuildType in Gradle.
In your
app/build.gradle
, use the following code snippet to query the current build type, and defineenableInstana
based on the build type.def buildType = gradle.startParameter.taskRequests.stream() .flatMap { it.args.stream() } .map { it.contains("Release") ? "Release" : it.contains("Debug") ? "Debug" : null} .filter(Objects::nonNull) .findFirst() buildType.ifPresent { println "buildType is ${it}" } def enableInstana = buildType.orElse("").matches("Debug")
-
Apply
Instana plugin
conditionally.if (enableInstana) { println "instana> apply instana plugin" apply plugin: 'com.instana.android-agent-plugin' }
-
Add the Instana Key conditionally in Gradle.
Then, you have an empty string in the
INSTANA_REPORTING_URL
field if Instana is disabled.android { defaultConfig { def instanaProperties = new Properties() instanaProperties.load(new FileInputStream("$project.projectDir/instana.properties")) buildConfigField 'String', 'INSTANA_KEY', enableInstana ? "${instanaProperties["instana.key"]}" : '""' buildConfigField 'String', 'INSTANA_REPORTING_URL', enableInstana ? "${instanaProperties["instana.reportingURL"]}" : '""' } }
-
Initialize the Instana Runtime conditionally.
Now, the Instana runtime will not be initialized with unwanted build type.
if (BuildConfig.INSTANA_REPORTING_URL.isNotBlank()) { Instana.setup(this, InstanaConfig( reportingURL = BuildConfig.INSTANA_REPORTING_URL, key = BuildConfig.INSTANA_KEY )) }
Sessions
The information that is captured by mobile Instana agents is organized in sessions.
Each session maps to an instance of the app; starts when the app is instantiated and ends when the app is stopped.
Session lifecycle
- A session automatically starts every time that the app is started, when the agent is set up
- A
sessionID
is automatically generated for the session - The
sessionID
remains unchanged while the app is alive (either in the foreground of the background) - All beacons that are sent by the Instana Android agent or iOS agent contains the same
sessionID
- The
sessionID
is discarded when the app is stopped; when the process itself is stopped - Next time the app is started, a new
sessionID
will be automatically generated
HTTP Monitoring
What HTTP information is monitored?
- The duration of the request
- HTTP method (
POST
,GET
....) - Full URL and path
- Status code (for example
200
) - Response sizes (header, body, decoded body)
- Any underlying error
- Backend tracing ID for backend correlation
What is the difference between auto and manual HTTP monitoring?
iOS
The iOS agent offers automatic and manual monitoring of HTTP sessions.
Automatic
To monitor HTTP requests and responses going through the URLSession, the automatic HTTP monitoring uses the Foundation's URLProtocol.
All captured requests and responses are reported to Instana. While the default URLSession
can be intercepted implicitly by URLProtocol
, all custom sessions require an explicit URLProtocol
registration
for monitoring. Because many applications have a custom URLSession
, the registration process for those sessions is not the ideal solution for the Instana iOS agent. To simplify the registration process, all sessions are registered
implicitly by swizzling the initializer of all URLSessions
. With the swizzling approach, no registration of the URLProtocol
is required and it simplifies automatic HTTP monitoring. Automatic monitoring of the
WKWebView
is not available since it's not reliable. The app and the WebView's WebKit
run in different processes. There is an IPC between the app and WebKit process but some data (for example POST body) is not
transmitted to the app process. This would lead to an unexpected behavior.
Manual
By capturing the HTTP request and response manually, the client can opt out from automatic monitoring and swizzling. No URLProtocol
is installed to the URLSessions
. Manual monitoring means that when you are capturing
HTTP requests and responses, it requires more effort to use the monitoring by the client.
Android
The Android agent offers automatic and manual monitoring of HTTP sessions.
Automatic
The Android plug-in weaves some additional tracking code in your app at compile time.
Instana currently supports automatic tracking of these network clients:
- OkHttp3
- HttpURLConnection
- Retrofit
Register your interest for support of more network clients in the Android agent's issue tracker.
Manual
By capturing the HTTP request and response manually, the client can opt out from automatic monitoring and take complete control over which network requests are tracked and which are not.
For more information, see Android API.
React Native
The React Native agent currently offers automatic of HTTP sessions.
Automatic
Refer to the documentation specific to each platform for more details about automatic monitoring of HTTP sessions.
iOS: Can I use my own URLProtocol
with automatic monitoring enabled?
Yes, you can create your own URLProtocol
to proxy your requests and responses through a custom URLSession
. Instana HTTP monitoring automatically ignores any URLSession
that has URLProtocol
as delegate. But you can also explicitly ignore any custom URLSession
from being monitored through Instana.ignore(yourURLSession)
. If you are using URLSession
inside your own URLProtocol
without a delegate, you should ignore this session in the Instana iOS agent. Otherwise, the request and response is double monitored.
iOS: Isn't swizzling dangerous?
Not always. Swizzling in the runtime is mostly done by adding a method:
func swizzled_touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// looks weird, but it calls the original implementation
swizzled_touchesBegan(touches, with: event)
print("do some custom magic here")
}
And then the new and old methods are exchanged through:
if let originalMethod = class_getInstanceMethod(UIResponder.self, #selector(touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?))),
let swizzledMethod = class_getInstanceMethod(UIResponder.self, #selector(swizzled_touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?))) {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
However, it might lead to unexpected behavior when the runtime makes a forward invocation like in UIResponder
. Sometimes the runtime performs message forwarding. This swizzling technique might cause a crash if a message (for example,
the new swizzled_touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
) is forwarded to another receiver on which the new method does not exist. In the Instana iOS agent, you cannot add a second method to the class.
Therefore, you set a new implementation directly (through a block) to the original selector and override the original implementation. The original implementation, temporarily stored, is then called inside the new function; so swizzling leaves
no traces.
iOS: Is monitoring for background sessions available?
No, because custom URLProtocol
subclasses are not available to background sessions. (See URLSession
doc.)
How does backend correlation work with HTTP requests?
All HTTP requests include automatic backend correlation, to backends that are monitored by Instana's host agent. You might not need to track or set anything client-side.
Which HTTP headers are being used?
To achieve backend correlation, the agent uses the following HTTP headers:
- Response Headers:
Server-Timing
Requirements
iOS
Which iOS versions are supported?
iOS: Instana iOS agent is compatible from iOS 11.
Which Swift versions are supported?
Swift 5 (since Xcode 10.2) or higher.
How do I install the iOS agent?
Use the Swift Package Manager inside Xcode. Alternatively, you can use CocoaPods
. To set up the Instana iOS agent, call one method in application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:
.
Android
Which Android versions are supported?
Minimum supported API level: Android API 16 (Android 4.1 "Jelly Bean").
AndroidX: AndroidX is supported and required.
Which Languages are supported?
Languages: Both Java and Kotlin are supported.
Java compatibility target: Java 1.8 or higher.
What does the Duplicate class com.google.common.util.concurrent.ListenableFuture
compilation error mean?
If your app has a dependency on guava, you might get the following compilation error after you add the Instana Android agent.
Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules guava-25.0-android.jar (com.google.guava:guava:25.0-android) and listenablefuture-1.0.jar (com.google.guava:listenablefuture:1.0)
To solve this problem, add the following dependency to your app:
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
What does the NoSuchMethodError: No virtual method log(Ljava/lang/String;)V in class Lokhttp3/internal/Platform;
runtime error mean?
This links to a well-known issue, which might occur when your applications resolved OkHttp
and OkHttp-logging-interceptor
versions differ. This situation is described in more lengths in: https://github.com/square/okhttp/issues/2839.
Instana Android agent uses OkHttp v4
, which might be newer than the OkHttp
.
To solve this problem, upgrade your applications OkHttp
and OkHttp-logging-interceptor
to the available versions.
What does the android.os.StrictMode$StrictModeDiskReadViolation
StrictMmode error mean?
Instana Android agent uses Java's UUIDs.
A well-known false positive is raised by StrictMode in Android API 18 and earlier: https://issuetracker.google.com/issues/36969031.
Workaround: Disable penaltyDeath
or detectDiskReads
for API 18 and earlier.
What does the java.lang.NoSuchMethodError: No virtual method setInitialDelay
compilation error mean?
Error: java.lang.NoSuchMethodError: No virtual method setInitialDelay(JLjava/util/concurrent/TimeUnit;)Landroidx/work/OneTimeWorkRequest$Builder; in class Landroidx/work/OneTimeWorkRequest$Builder; or its super classes (declaration of 'androidx.work.OneTimeWorkRequest$Builder'
WorkManager 2.1.0 changed the method signature for setInitialDelay
. Before WorkManager 2.1.0:
abstract class WorkRequest {
abstract static class Builder<B extends Builder, W extends WorkRequest> {
}
}
class OneTimeWorkRequest extends WorkRequest {
static class Builder extends WorkRequest.Builder<Builder, OneTimeWorkRequest> {
public @NonNull Builder setInitialDelay(long duration, @NonNull TimeUnit timeUnit) {
....
}
}
}
After WorkManager 2.1.0:
abstract class WorkRequest {
abstract static class Builder<B extends Builder, W extends WorkRequest> {
public @NonNull B setInitialDelay(long duration, @NonNull TimeUnit timeUnit) {
...
}
}
}
class OneTimeWorkRequest extends WorkRequest {
static class Builder extends WorkRequest.Builder<Builder, OneTimeWorkRequest> {
}
}
In effect, every dependency in a project needs to exclusively use WorkManager 2.1.0+ or earlier versions.
Instana Android agent uses WorkManager 2.4.0+.
If you get this error, the most probable issue is that another dependency is using an older version of WorkManager. Make sure to update it.
What does the Required: PROJECT. Found: EXTERNAL_LIBRARIES, PROJECT, SUB_PROJECTS
compilation error mean?
This error is known to open when a Gradle plug-in, which requires an Android Gradle plug-in older than 3.6.1 is compiled by using Android Gradle plug-in 3.6.1 or higher.
For instance, by using Realm Database plug-in 7.0.1 with Android Gradle plug-in 4.0.1 and Instana Android agent 3.4.0 can give way to this compilation error. The resulting error log contains a reference to Realm's transformer task's failure first, and then maybe to some other plug-in (not relevant):
[...]
Task :app:transformClassesWithRealmTransformerForDevevelopDebug FAILED
[...]
To solve this issue, try to upgrade the offending plug-in.
Alternatively, either:
-
Make sure that the Instana Android agent plug-in is started after the offending plug-in. For example,
apply plugin: 'com.android.application' apply plugin: 'realm-android' apply plugin: 'com.instana.android-agent-plugin'
-
Downgrade your app's Android Gradle plug-in to the one that the offending plugging requires
What does the Problem processing attributes...
compilation error in ajc-transform
mean?
As of today, it seems like one of the bytecode transformations that are applied by the Firebase Performance plug-in has the adverse effect of preventing the Instana Android agent from doing its job.
To prevent the issue, make sure that Instana's Android agent is run before Firebase Performance plug-in.
You can achieve this by changing the order in which you add each plug-in into your project:
apply plugin: 'com.instana.android-agent-plugin' // Instana agent will be applied before Firebase Performance
apply plugin: 'com.google.firebase.firebase-perf'
What does the Unable to find method...
compilation error mean?
Each major Instana Android agent version is compatible with a specific Android Gradle plug-in branch.
This error is most likely to show up when the Android Gradle plug-in being used isn't supported by the Instana Android agent.
Refer to the Android Gradle plug-in and Gradle version section of the documentation to check the compatibility matrix and learn where to find your app's current Android Gradle plug-in version.
What does the Failed resolution of: Landroidx/work/impl/utils/futures/AbstractFuture
runtime error mean?
The whole error reads: Fatal Exception: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/work/impl/utils/futures/AbstractFuture;
It might happen if your app dependencies at some point required a dependency on 9999.0-empty-to-avoid-conflict-with-guava
but it no longer requires it.
If your app's contains the following dependency, try removing it:
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
What does the Execution failed for task ':app:transformClassesWithDexBuilderFor...'
compilation error mean?
The whole error reads (for the DevDebug
flavor, for instance):
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:transformClassesWithDexBuilderForDevDebug'.
> There were multiple failures while executing work items
> A failure occurred while executing com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform$DexConversionWorkAction
> Failed to process /Users/developer/Projects/mobile-app/android/app/build/intermediates/javac/devDebug/classes
[...]
This error highlights a mismatch between the Instana agent version and the Android Gradle plug-in versions. Refer to the platform-specific installation instructions to find out about the supported combinations.
React Native
The Instana React Native agent invokes iOS agent on the iOS platform and invokes Android agent on the Android platform. iOS agent or Android agent might be upgraded with React Native agent upgrade. Refer to the documentation specific to each platform for more details.
How to clean up the cached iOS agent and Android agent?
When the React Native agent is upgraded to a new version from your mobile app, run the following command from terminal to thoroughly clean-up the cached old version of iOS agent and Android agent:
cd android && ./gradlew clean
cd ..
cd ios && pod cache clean --all && rm -rf build
cd ..
rm -rf node_modules
yarn cache clean --force
yarn install
cd ios && pod install
Sensitive data
Are you collecting data, which can uniquely identify users?
By default, the Instana agent does not include data, which can identify unique users. Additionally, the agent also does not apply techniques such as device fingerprinting.
User-specific data can be made available to Instana through the iOS user API or the Android user API.
What are you doing with the user data transmitted to Instana?
The Instana agent can be configured by customers to transmit user-identifying information to Instana. This information is only used to provide the features visible to you within Instana. Instana does not interpret this data in any other way, nor is it correlated across customers.
Is it possible to delete user data after it is transmitted to Instana?
Infrequent deletion requests, for example to comply with GDPR, are supported. If you expect frequent or periodic deletion requests, instead transmit anonymized data to Instana (for example hashed user IDs).
Are you anonymizing IPs?
Yes, IPs are anonymized. By default, the last octet of IPv4 addresses and the last 80 bits of IPv6 addresses are set to zeros. Stricter anonymization rules can be configured through the configuration tab in a mobile app's dashboard within the Instana user interface.