Android monitoring API

You can use the Instana Android agent API to monitor your Android applications.

Instana Android agent

You can use the Instana Android agent through the Instana class methods.

Setting up Instana monitoring

To set up the Instana monitoring for Android applications, initialize Instana in your Application class' onCreate(), immediately after super.onCreate():

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Instana.setup(
            this,
            InstanaConfig(
                key = "YOUR_APP_KEY",
                reportingURL = "YOUR_REPORTING_URL"
            )
        )
    }
}

Configuration parameters

Parameter
Description
key (String) The Instana monitoring configuration key.
reportingURL (String) The URL pointing to the Instana instance to which the monitoring data is sent.
httpCaptureConfig (HTTPCaptureConfig, optional) By default, HTTP requests and responses are captured automatically. To disable the automatic monitoring, set this parameter to HTTPCaptureConfig.MANUAL. To turn off the HTTP session monitoring, set this parameter to HTTPCaptureConfig.NONE.
suspendReporting (SuspendReportingType, optional) Transmission of Instana beacons happens with low priority in the background. You can choose the conditions under which the transmission of beacons must be suspended, such as when the battery is low, when you have only a cellular connection, or never.
initialBeaconDelayMs (Long, optional) The agent delays the transmission of the first beacons for the determined time to make sure that the client sets up all the additional parameters, such as Session Identifiers, before the agent sends any beacon to the Instana server. Only the transmission of the beacons are delayed. The monitoring and capturing of beacons start as soon as the agent is initialized, regardless of the initialBeaconDelayMs parameter.
collectionEnabled (Bool, optional) This parameter enables or disables the Android agent's data collection and submission on startup. By default, the data collection is turned on with the setup. To set up Instana but ignore any data collection, set this parameter to false in the setup. This parameter is useful for scenarios in which user consent is required before the Android agent can collect data. The default value is true.
enableCrashReporting (Boolean, optional) (public preview) This parameter enables or disables the crash data collection and submission on startup. If required, the collection and submission can be enabled after startup. This parameter is useful for scenarios in which user consent is required before the Android agent can collect crash data. The default value is false.
slowSendIntervalMillis (Long, optional) This parameter enables the slow sending mode feature on beacon sending failure by providing a valid positive integer in milliseconds (range from 2000-3600000 milliseconds). The default value is null, which means that the slow sending mode is disabled.
usiRefreshTimeIntervalInHrs (Long, optional) This parameter determines the time interval for refreshing the usi (userSessionIdentifier). The usi serves as a unique identifier, which is assigned to the application when identifying user data is not explicitly provided or when the application doesn't possess any user context. If this parameter is set to a negative value, the usi retains its default behavior and never refreshes. If this parameter is set to a value of zero, the usi is not sent to the backend, and thus the identifier is deactivated. If this parameter is set to a positive value, the usi refreshes at the specified time intervals. The parameter value needs to be provided in hours. The default value is `-1.
autoCaptureScreenNames (Boolean, optional) (public preview) This parameter enables automatic capturing of screen names. Currently, it supports screen name capture for Android applications that are built by using Fragments and Activities with xml layouts (not applicable to composable or other UIs). Enabling this feature removes the need for the existing Instana.view implementation in the codebase, as it serves as a replacement.

Screen names are captured at multiple levels as follows:

* Activity
* Fragments

Activity: Name is automatically extracted from accessibility labels that are assigned to the root layout. If not found, the Activity class name is used as the screen name.
Fragments: The agent first looks for labels in the navController, then in the fragment tags, and later in accessibility labels on the root view. If none are available, it uses the Fragment class name as the screen name.

Metadata for each captured view includes the local path, OnResume time (you might see a minor difference in actual and captured resume time as it is collected from callbacks), and class names of Fragments and Activities. It's important to note that auto capture is only functional for applications with minify disabled or pro-guard excluded for all Fragments as of now. The default value is false.

Checking current configuration

To check the current Instana configuration, access the InstanaConfig instance:

val currentConfig = Instana.config

Retrieving the session identifier

Each Instana agent instance has a unique session identifier that you might use for other purposes in your app.

Property
Description
sessionId (String, optional) The current session identifier. This session ID is created within the setup process.

Example

val sessionId = Instana.sessionId

Automatic HTTP monitoring

By default, HTTP sessions are captured automatically. Upon initializing Instana (after you install the Instana Android plug-in and Instana Android SDK), the agent takes care of the rest.

The Instana Android agent automatically weaves code to provide monitoring of HTTP requests for the supported clients:

  • OkHttp3
  • HttpURLConnection
  • Retrofit

Automatic HTTP monitoring can be disabled in favor of manual HTTP monitoring.

Manual HTTP monitoring

You can also monitor HTTP sessions manually.

Starting capture

This function returns the HTTPMarker, which you need later when the request is completed.

Instana {
    fun startCapture(url: String, viewName: String? = view, requestHeaders: Map<String,String>?): HTTPMarker?
}
Configuration parameters
Parameter
Description
url (String) The URL to capture.
viewName (String, optional) The name of the visible view that is related to this request.
requestHeaders (Map<String,String>, optional) The name and values for the request header.

This function returns the HTTP marker that you can use to set the response size and call the finish or error state when the request is completed.

Finishing capture

After the request is completed, you must call finish with the response on the HTTPMarker and an optional Error:

HTTPMarker {
    fun finish(response: okhttp3.Response)
    fun finish(request: okhttp3.Request, error: Throwable)
    fun finish(connection: java.net.HttpURLConnection)
    fun finish(connection: java.net.HttpURLConnection, error: Throwable)
    fun finish(data: com.instana.android.instrumentation.HTTPMarkerData)
}

Cancelling capture

If the request is canceled before completion, start the following method on HTTPMarker:

fun cancel()

Examples

val request = yourMethodToCreateRequest()
val marker = Instana.startCapture(request.url().toString(), viewName: "User Details")
val response = OkHttpClient().newCall(request).execute()
marker?.finish(response)
val marker = Instana.startCapture("https://example.com/user", viewName: "User Details")
// Complete request and manually obtain any relevant information
val httpMarkerData = HTTPMarkerData(
            requestMethod = "GET",
            responseStatusCode = 200,
            responseSizeEncodedBytes = 200,
            responseSizeDecodedBytes = 1000
        )
marker?.finish(httpMarkerData)
HTTPMarker marker = Instana.startCapture("https://example.com/user", "User Details");
// Complete request and manually obtain any relevant information
HTTPMarkerData data = new HTTPMarkerData.Builder()
        .requestMethod("GET")
        .responseStatusCode(200)
        .responseSizeEncodedBytes(200)
        .responseSizeDecodedBytes(1000)
        .build();
marker.finish(data);

Setting views

Instana can segment mobile app insights by logical views. To do so, set the view name through the Instana.setView(String) method. The view is then associated to all monitored beacons until the view changes when setView is called again.

Do not use technical or generic names like the Class (for example, WebViewActivity) to define views. Use readable names for views, for example, product detail page or payment selection. By focusing on user experience, team members without intimate knowledge of the codebase can understand the insights that are provided.

Instana.setView(String) must be called when a screen is presented to the user, rather than when a screen is created (as in a Fragment, which can be created once but shown multiple times). Setting the view name also enables Instana to track page transitions in addition to page loads.

Example

class WebViewActivity : AppCompatActivity() {

    override fun onResume() {
        super.onResume()
        Instana.view = "Webview: FitBit authorization"
    }
}

Identifying users

User-specific information can optionally be sent with data that is transmitted to Instana. This information can then be used to unlock the following extra capabilities:

  • Calculating the number of users affected by errors
  • Filtering data for specific users
  • Identifying the user who initiated a view change or HTTP request

By default, Instana associates any user-identifiable information to beacons. Be aware of the respective data protection laws when you choose to send user-specific information to Instana. Identify users through a user ID. For Instana, this action is a transparent String that is only used to calculate certain metrics. userName and userEmail can also be used to have access to more filters and a more pleasant presentation of user information.

If you handle anonymous users and thus don't have access to user IDs, you can alternatively use session IDs. Session IDs are not as helpful as user IDs when you filter data, but they are a good indicator to calculate affected or unique user metrics. You must set a username, such as Anonymous to have a clear differentiation between authenticated and unauthenticated users. Session IDs can be sensitive data (depending on the framework or platform used). To avoid transmitting data to Instana that can grant access, hash session IDs.

Data already transmitted to the Instana backend cannot be retroactively updated. Therefore, you must call this API as early as possible in the app launch process.

If user data is not provided or the application lacks any user context, the usi (userSessionIdentifier) is retrieved from the beacon. The usi functions as a distinct identifier, which is assigned to the application for uniquely identifying users in scenarios where user data is not available. By using the usiRefreshTimeIntervalInHrs parameter in the Configuration parameters section, you can specify the time interval for refreshing the usi.

Instana {
    void setUserId(@Nullable String)
    @Nullable String getUserId()
    void setUserName(@Nullable String)
    @Nullable String getUserName()
    void setUserEmail(@Nullable String)
    @Nullable String getUserEmail()
}

Example

class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()
        Instana.setup(
            this,
            InstanaConfig(
                key = BuildConfig.INSTANA_KEY,
                reportingURL = BuildConfig.INSTANA_REPORTING_URL
            )
        )
        Instana.userId = "1234567890"
        Instana.userEmail = "instana@example.com"
        Instana.userName = "instana android agent demo"
    }
}

Adding metadata

Arbitrary metadata can optionally be attached to all data transmitted to Instana. You can use this metadata to track UI configuration values, settings, feature flags, and any additional context that might be useful for analysis.

Currently, up to 50 meta key or value pairs are supported. The key can be up to 98 characters, and the value can be up to 1024 characters.

Instana {
     val meta = MaxCapacityMap<String, String>(50)
}

Properties

Parameter
Description
meta (MaxCapacityMap) The object that holds all meta key or value pairs. Its interface resembles that of a common Map. You can add and remove elements as usual, if you don't go over the object's maximum capacity.

Example

class UserProfileActivity : AppCompatActivity() {

    override fun onResume() {
        super.onResume()
        Instana.meta.put("user authenticated", "true")
        Instana.meta.put("user type", "editor")
    }
}

Excluding URLs from monitoring

URLs can be ignored by providing regular expressions, by adding them to the ignoreURLs list. A good scenario for usage of this function would be to ignore all HTTP requests that contain any sensitive data like a password.

Only automatically monitored URLs are ignored. Manually monitored URLs are not ignored.

Instana {
    val ignoreURLs = mutableListOf<Regex>()
}
Instana {
    List<Pattern> getIgnoreURLs()
}

Example

class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()
        Instana.setup(
            this,
            InstanaConfig(
                key = BuildConfig.INSTANA_KEY,
                reportingURL = BuildConfig.INSTANA_REPORTING_URL
            )
        )
        Instana.ignoreURLs.add("/.*([&?])password=.*/i".toRegex())
    }
}

The example ignores all URLs that contain a password in the query.

Reporting custom events

Custom events enable reporting about nonstandard activities, important interactions, and custom timings to Instana. This reporting can be especially helpful to analyze undetected errors (breadcrumbs) and to track extra performance metrics.

Instana {
    fun reportEvent(event: CustomEvent)
}

With CustomEvent provided by Instana, you can set multiple parameters, eventName (in its constructor) being the only mandatory one.

Configuration parameters

Parameter
Description
eventName (String) Name for the custom event. It is prominently shown in the Instana Dashboard
startTime (Long, optional) Timestamp in which the event started, which is defined in milliseconds since Epoch. Defaults to Now()-duration.
duration (Long, optional) Duration of the event, which is defined in milliseconds. Defaults to 0.
viewName (String, optional) Logical view in which the event happened. Defaults to the current view set in Instana.view.
meta (Map<String, String>, optional) Map of meta values. These values are merged with the global Instana.meta tags for this event. They won't be applied to any other future event. Do not include sensitive information with meta.
backendTracingID (String, optional) Tracing ID that is sent by the Instana-enabled backend in the Server-Timing header as intid;desc=backendTracingID.
error (Throwable, optional) Error that is thrown to provide extra context, if any.
customMetric (Double, optional) Option for supplying custom metric data with precision up to four decimal places. Do not include sensitive information in this metric.

Examples

val myEvent = CustomEvent("MyCustomEvent").apply {
    duration = 300
    meta = mapOf("keyOne" to "valueOne", "keyTwo" to "valueTwo")
    backendTracingID = "1234567890"
    customMetric = 98.7654
}

Instana.reportEvent(myEvent)
Map<String,String> myMetas = new HashMap<>();
myMetas.put("keyOne", "valueOne");
myMetas.put("keyTwo", "valueTwo");

CustomEvent myEvent = new CustomEvent("MyCustomEvent");
myEvent.setDuration(300L, TimeUnit.MILLISECONDS);
myEvent.setMeta(myMetas);
myEvent.setBackendTracingID("1234567890");

Instana.reportEvent(myEvent);

Availability of Google Play services

You can explicitly tell Instana whether Google Play services are available for a specific user and session.

Instana {
    val googlePlayServicesMissing: Boolean?
}

Example

class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()
        Instana.setup(
            this,
            InstanaConfig(
                key = BuildConfig.INSTANA_KEY,
                reportingURL = BuildConfig.INSTANA_REPORTING_URL
            )
        )
        Instana.googlePlayServicesMissing = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) != ConnectionResult.SUCCESS
    }
}
//app/build.gradle
dependencies {
    implementation 'com.google.android.gms:play-services-basement:17.1.1'
    implementation 'com.google.android.gms:play-services-base:17.1.0'
}

Logging facade

By default, Instana logs directly into LogCat. You can pipe these logs by providing an object that implements the Logger interface:

interface Logger {
    fun log(level: Int, tag: String, message: String, error: Throwable?)
}

Instana {
    var logger: com.instana.android.Logger?
}

Configuration parameters

Parameter
Description
level (Int) Log level defined by one of android.util.Log levels (android.util.Log.INFO, android.util.Log.ERROR, ...)
tag (String) Internal Instana Agent tag
message (String) Log message generated by Instana
error (Throwable, optional) Error that is thrown to provide more context, if any.

Example

Instana.logger = object : Logger {
    override fun log(level: Int, tag: String, message: String, error: Throwable?) {
        Log.d("my_tag", "intercepted Instana Android Agent log message: '$message'")
    }
}

Defining logging levels

By default, Instana generates INFO level logs. You change this default by defining any log level out of the common android.util.Log levels (android.util.Log.INFO, android.util.Log.ERROR, or other levels):

Instana {
    var logLevel: Int
}

Example

Instana.logLevel = android.util.Log.ERROR

Enabling or disabling data collection

You can enable data collection and submission at any time, such as when the Instana agent starts or during the runtime.

This feature is most useful in scenarios where explicit user consent is required before the collection of data can proceed.

Instana {
    fun setCollectionEnabled(enabled: Boolean)
    fun isCollectionEnabled()
}

Example

Instana.setCollectionEnabled(true)

Redacting URL Query parameters

Query parameters in collected URLs might contain sensitive data. Therefore, the Instana agent supports the specification of regex patterns for query parameter keys whose values must be redacted; any redacted value is replaced with <redacted>.

Redaction happens within the Instana agent before the agent reports to the Instana backend. Therefore, secrets do not reach the Instana backends for processing and are not available for analysis in the UI or retrieval by using Instana API.

By default, the Instana agent is configured with a list of three regex patterns to automatically redact query parameter values:

  • key
  • secret
  • password

Redaction is only applied to automatically monitored requests and their associated logs. Manually monitored requests are not redacted.

Instana {
    val redactHTTPQuery = mutableListOf<Regex>()
}

Example

class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()
        Instana.setup(
            this,
            InstanaConfig(
                key = BuildConfig.INSTANA_KEY,
                reportingURL = BuildConfig.INSTANA_REPORTING_URL
            )
        )

        // in order to for example redact "https://example.com?secret=abcdef" into "https://example.com?secret=<redacted>"
        Instana.redactHTTPQuery.add("secret".toRegex())
        // in order to for example redact "https://example.com?hidden1=abcdef&hidden2=123456" into "https://example.com?hidden1=<redacted>&hidden2=<redacted>"
        Instana.redactHTTPQuery.add("^hidden[0-9]".toRegex())
    }
}

Capturing HTTP headers

Optionally, the Instana agent can capture the HTTP headers of every tracked request or response.

A list of regex patterns can be defined to determine which headers are captured.

If the same header name is present in both a request and its response, only the response's header value is kept.

Instana {
    val captureHeaders = mutableListOf<Regex>()
}

Example

class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()
        Instana.setup(
            this,
            InstanaConfig(
                key = BuildConfig.INSTANA_KEY,
                reportingURL = BuildConfig.INSTANA_REPORTING_URL
            )
        )

        // in order to capture all request/response headers like: "X-MyCompany-name1", "X-MyCompany-name2"...
        Instana.captureHeaders.add("X-MyCompany-.*".toRegex())
    }
}

Enabling slow sending mode

The slow sending mode feature is disabled by default. If required, you can enable this feature.

By default, if a beacon sending fails, the Instana agent tries to resend the beacon until the sending is successful. This resending doesn't work well with some cellular networks. By enabling the slow sending mode feature, the beacon sending interval is changed to the time value that is assigned to the slowSendIntervalMillis parameter. Each beacon sending consists of only one beacon instead of a batch (a maximum of 100 beacons in a batch). The Instana agent stays in slow sending mode until one beacon is sent successfully.

The valid time range for slowSendIntervalMillis is 2000-3600000 milliseconds.

Example

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Instana.setup(
            this,
            InstanaConfig(
                key = BuildConfig.INSTANA_KEY,
                reportingURL = BuildConfig.INSTANA_REPORTING_URL,
                slowSendIntervalMillis = 60000
            )
        )
    }
}

Tracing user session ID

By default, the user session is tracked, and the ID is a randomly generated Universally Unique Identifier (UUID). This ID remains unchanged while the app is installed. You can configure the expiration time of the user session ID by using the usiRefreshTimeIntervalInHrs parameter. The following parameter values indicate the status of the user session ID:

  • Negative number: This value indicates that the user session ID never expires. The default value is -1.

  • Positive number: This value means that the user session ID is refreshed after the set time, that is, a new UUID is generated and used.

  • Zero: This value denoted by 0.0 means that the user session ID is disabled.

Example

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Instana.setup(
            this,
            InstanaConfig(
                key = BuildConfig.INSTANA_KEY,
                reportingURL = BuildConfig.INSTANA_REPORTING_URL,
                usiRefreshTimeIntervalInHrs = 24
            )
        )
    }
}

Capturing composable UI name

To automatically capture the screen names of composable UIs, you can add addInstanaObserver() extension function to the NavHostController object in your composable application. This function collects names of the route path that are specified for composable navigation.

Example

@Composable
fun RootNavigationGraph(navHostController: NavHostController, context: Context) {
    NavHost(
        navController = navHostController,
        route = Graph.ROOT,
        startDestination = Graph.INITIAL_FLOW,
    ) {
        initNavGraph(navHostController, context)
        composable(route = Graph.HOME) {
            navHostController.addInstanaObserver() //Adding Instana observer as a extension function.
            HomeScreen()
        }
    }
}