# Supported instrumentations

Copy as Markdown[Open in ChatGPT](https://chatgpt.com/?q=Read%20https%3A%2F%2Fcoralogix.com%2Fdocs%2Fuser-guides%2Frum%2Fsdk-installation%2Fandroid%2Ffeatures%2Fsupported-instrumentations.md%20and%20help%20me%20with%20my%20question%20about%20this%20Coralogix%20documentation%20page.)[Open in Claude](https://claude.ai/new?q=Read%20https%3A%2F%2Fcoralogix.com%2Fdocs%2Fuser-guides%2Frum%2Fsdk-installation%2Fandroid%2Ffeatures%2Fsupported-instrumentations.md%20and%20help%20me%20with%20my%20question%20about%20this%20Coralogix%20documentation%20page.)

## Supported Instrumentations[​](#supported-instrumentations "Direct link to Supported Instrumentations")

| Instrumentation      | Description                                                   |
| -------------------- | ------------------------------------------------------------- |
| **Logs**             | Structured logging with severity and labels (called `Custom`) |
| **Errors**           | Uncaught & handled exceptions                                 |
| **Network**          | Request/response performance data                             |
| **ANR**              | ANR tracking                                                  |
| **Mobile Vitals**    | CPU, FPS, memory, and cold/warm start times.                  |
| **Custom Metrics**   | User-defined numeric metrics                                  |
| **Lifecycle**        | Report lifecycle events.                                      |
| **User Interaction** | Report user interactions in the application.                  |
| **Navigation**       | Report navigation events                                      |

### Logs (Custom)[​](#logs-custom "Direct link to Logs (Custom)")

Send a simple log with optional data and labels.

#### Example[​](#example "Direct link to Example")

```
CoralogixRum.log(

    severity = CoralogixLogSeverity.Info,

    message = "User logged in successfully",

    data = mapOf("userId" to "12345"), // optional

    labels = mapOf("environment" to "staging") // optional

)
```

#### Disabling this feature[​](#disabling-this-feature "Direct link to Disabling this feature")

You can disable this instrumentation by passing `false` in the `instrumentations` map in `CoralogixOptions`. Any call to `log()` would be ignored if the instrumentation in disabled:

```
val options = CoralogixOptions(

    // ... other options ...

    instrumentations = mapOf(

        Instrumentation.Custom to false

    )

)
```

Note

The passed `labels` map will be added to other labels set in the SDK for **this event only**.

### Error Reporting[​](#error-reporting "Direct link to Error Reporting")

The Coralogix SDK automatically captures unhandled crashes and exceptions through its built-in Error Instrumentation module.

#### Automatic Crash Tracking[​](#automatic-crash-tracking "Direct link to Automatic Crash Tracking")

Once the SDK is initialized and the error instrumentation is enabled, all unhandled exceptions and app crashes are automatically detected and sent to Coralogix.

#### Manual Error Reporting[​](#manual-error-reporting "Direct link to Manual Error Reporting")

You can manually report handled exceptions when you want visibility into recoverable or expected failures, such as API errors or business logic exceptions.

##### Example[​](#example-1 "Direct link to Example")

```
try {

    riskyOperation()

} catch (t: Throwable) {

    CoralogixRum.reportError(t)

}
```

##### Attaching custom attributes[​](#attaching-custom-attributes "Direct link to Attaching custom attributes")

For richer error reporting, pass a `CoralogixErrorDecorator` with `customAttributes`. The attributes are emitted on the resulting RUM error event under the `data` field of `errorContext` (matching the iOS SDK).

```
val decorator = CoralogixErrorDecorator(

    throwable = t,

    isCrash = false

).copy(

    customAttributes = mapOf(

        "userId" to "12345",

        "screen" to "checkout"

    )

)

CoralogixRum.reportError(decorator)
```

##### Bundling a message, data, and labels[​](#bundling-a-message-data-and-labels "Direct link to Bundling a message, data, and labels")

`reportError(throwable, ...)` also accepts optional `data` and `labels`, so you can attach context in a single call instead of a separate `log()`. `data` is emitted under `error_context.error_custom_data` and `labels` are merged into the event's labels.

```
try {

    riskyOperation()

} catch (t: Throwable) {

    CoralogixRum.reportError(

        throwable = t,

        data = mapOf("cart_size" to 3, "reason" to "timeout"),

        labels = mapOf("team" to "payments")

    )

}
```

#### Disabling this feature[​](#disabling-this-feature-1 "Direct link to Disabling this feature")

You can disable this instrumentation by passing `false` in the `instrumentations` map in `CoralogixOptions`. Any call to `reportError()` would be ignored if the instrumentation in disabled:

```
val options = CoralogixOptions(

    // ... other options ...

    instrumentations = mapOf(

        Instrumentation.Error to false

    )

)
```

### Network Events Reporting[​](#network-events-reporting "Direct link to Network Events Reporting")

To enable RUM to intercept network events, add `CoralogixOkHttpInterceptor` to your network client (or use the `Coralogix Gradle Plugin`).

#### Examples[​](#examples "Direct link to Examples")

##### OkHttp[​](#okhttp "Direct link to OkHttp")

```
val okHttpClient = OkHttpClient.Builder()

    .addInterceptor(CoralogixOkHttpInterceptor())

    .build()



val request = Request.Builder()

    .url("https://api.example.com/data")

    .build()



val response = okHttpClient.newCall(request).execute()

println(response.body?.string())
```

##### Retrofit[​](#retrofit "Direct link to Retrofit")

```
val okHttpClient = OkHttpClient.Builder()

    .addInterceptor(CoralogixOkHttpInterceptor())

    .build()



val retrofit = Retrofit.Builder()

    .baseUrl("https://api.example.com/")

    .client(okHttpClient)

    .addConverterFactory(GsonConverterFactory.create())

    .build()



interface ApiService {

    @GET("data")

    suspend fun getData(): Response<DataModel>

}



val apiService = retrofit.create(ApiService::class.java)

val response = apiService.getData()

println(response.body())
```

##### Ktor[​](#ktor "Direct link to Ktor")

```
val httpClient = HttpClient(OkHttp) {

    engine {

        preconfigured = OkHttpClient.Builder()

            .addInterceptor(CoralogixOkHttpInterceptor())

            .build()

    }

}



val response = httpClient.get("https://api.example.com/data")

println(response.bodyAsText())
```

#### Disabling this feature[​](#disabling-this-feature-2 "Direct link to Disabling this feature")

You can disable this instrumentation by passing `false` in the `instrumentations` map in `CoralogixOptions`:

```
val options = CoralogixOptions(

    // ... other options ...

    instrumentations = mapOf(

        Instrumentation.Network to false

    )

)
```

Note

Only `OkHttp` clients are currently supported.

### ANR Events Reporting[​](#anr-events-reporting "Direct link to ANR Events Reporting")

The Coralogix SDK automatically captures and report ANR events, ANR events are reported as an error.

#### Disabling this feature[​](#disabling-this-feature-3 "Direct link to Disabling this feature")

You can disable this instrumentation by passing `false` in the `instrumentations` map in `CoralogixOptions`:

```
val options = CoralogixOptions(

    // ... other options ...

    instrumentations = mapOf(

        Instrumentation.Anr to false

    )

)
```

### Mobile Vitals Reporting[​](#mobile-vitals-reporting "Direct link to Mobile Vitals Reporting")

The Mobile Vitals instrumentation continuously monitors your app’s performance and responsiveness, providing real-time visibility into user experience quality. It automatically tracks key system metrics, periodic snapshots, and one-time events that represent critical app behaviors like cold starts or frame drops.

#### What We Measure[​](#what-we-measure "Direct link to What We Measure")

| Category                | Metric                                     | Description                                                                                              |
| ----------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------- |
| **Frame Rendering**     | **FPS (Frames Per Second)**                | Measures how smoothly your app renders frames. Low FPS indicates UI stutters or heavy rendering work.    |
| **Frame Quality**       | **Slow Frames / Frozen Frames**            | Tracks frames that exceeded normal rendering budgets (slow) or were completely stuck (frozen).           |
| **CPU Usage**           | **Total / Main Thread CPU**                | Captures overall and main-thread CPU usage percentage and timing, helping identify CPU-heavy operations. |
| **Memory Usage**        | **Resident / Heap / Java / Native Memory** | Tracks memory utilization from both Java and native layers to identify leaks or memory pressure.         |
| **Startup Performance** | **Cold Start / Warm Start Time**           | Measures how long it takes for the app to become ready when launched cold or resumed from background.    |

#### Aggregation Reports[​](#aggregation-reports "Direct link to Aggregation Reports")

The SDK continuously aggregates performance data and periodically sends it to Coralogix as Mobile Vitals Aggregations. These reports summarize metrics like average CPU load, memory usage, and FPS over time. Reports are meant to be tied to a specific view context, to implement this idea a report is being sent on one of two scenarios:

* The view context has changed (navigation has occurred)
* No mobile vitals event was reported for at least 15 seconds (no navigation)

#### One Shot Events[​](#one-shot-events "Direct link to One Shot Events")

Alongside periodic summaries, the SDK reports important one-time measurements that occur during specific lifecycle moments:

| Event          | Description                                                           |
| -------------- | --------------------------------------------------------------------- |
| **Cold Start** | Time taken from process creation until the first activity is visible. |
| **Warm Start** | Time taken when resuming the app from background.                     |

These one-shot events are sent as soon as they occur, giving you instant visibility into startup performance and user flow responsiveness.

#### Disabling this feature[​](#disabling-this-feature-4 "Direct link to Disabling this feature")

You can disable this instrumentation by passing `false` in the `instrumentations` map in `CoralogixOptions`:

```
val options = CoralogixOptions(

    // ... other options ...

    instrumentations = mapOf(

        Instrumentation.MobileVitals to false

    )

)
```

You can also disable specific metric collection by passing `false` for a specific detector in the `mobileVitalsOptions` map in `CoralogixOptions` For example to disable cpu usage:

```
val options = CoralogixOptions(

    // ... other options ...

    mobileVitalsOptions = mapOf(

        MobileVitalType.CpuUsage to false // for example

    )

)
```

### Custom Metrics[​](#custom-metrics "Direct link to Custom Metrics")

Send arbitrary key-value pairs.

#### Example[​](#example-2 "Direct link to Example")

```
CoralogixRum.sendCustomMeasurement("image_upload_time_ms", 1480L)
```

### Custom Time Measurement[​](#custom-time-measurement "Direct link to Custom Time Measurement")

Measure the elapsed time of any operation.

#### Example[​](#example-3 "Direct link to Example")

```
CoralogixRum.startTimeMeasure("image-load", mapOf("source" to "network"))

loadImage()

CoralogixRum.endTimeMeasure("image-load")
```

See the [Custom Time Measurement](#custom-time-measurement) section in the API Reference for full behaviour details.

### Lifecycle Events Reporting[​](#lifecycle-events-reporting "Direct link to Lifecycle Events Reporting")

Captures app lifecycle activity and fragment events that occur during runtime, providing insights into the application's behavior and performance.

* Activity lifecycle events:

  * onActivityCreated - Triggered when the activity is first created, initializing the activity and setting up the UI.
  * onActivityStarted - Called when the activity becomes visible to the user, but may not yet be interactive.
  * onActivityResumed - Invoked when the activity enters the resumed state, making it fully interactive and allowing user input.
  * onActivityPaused - Called when the activity is partially obscured, such as when another activity or a dialog appears, but the activity is still partially visible.
  * onActivityStopped - Triggered when the activity is no longer visible to the user and enters the stopped state.
  * onActivitySaveInstanceState - Called to save the current state of the activity (e.g., UI data, user input) so it can be restored if the activity is restarted.
  * onActivityDestroyed - Called just before the activity is destroyed, allowing for final cleanup of resources and references.

* Fragment lifecycle events:

  * onFragmentAttached - Called when the fragment is attached to its host activity. This is the point where the fragment is associated with the activity lifecycle.
  * onFragmentCreated - Called when the fragment is created. This occurs only once per fragment instance, even if it is attached and detached multiple times.
  * onFragmentViewCreated - Called after the fragment’s view is created and fully inflated. At this point, the fragment's UI is ready.
  * onFragmentStarted - Triggered when the fragment enters the started phase and becomes visible to the user.
  * onFragmentResumed - Called when the fragment enters the resumed phase, meaning the fragment is now interactive and the user can interact with it.
  * onFragmentPaused - Called when the fragment is partially obscured by another UI element (e.g., another activity, dialog box), but still visible.
  * onFragmentStopped - Called when the fragment is no longer visible to the user and has entered the stopped state.
  * onFragmentSaveInstanceState - Called to save the fragment's state (e.g., UI data, input) when the system needs to save its state (during pauses, backgrounding, or configuration changes), so it can be restored later.
  * onFragmentViewDestroyed - Called when the fragment’s view is destroyed and is no longer available, typically when the fragment is removed or replaced.
  * onFragmentDestroyed - Called when the fragment instance is fully destroyed, releasing any remaining resources.
  * onFragmentDetached - Called when the fragment is detached from its host activity, ending the association between the fragment and its host.

#### Disabling this feature[​](#disabling-this-feature-5 "Direct link to Disabling this feature")

You can disable this instrumentation by passing `false` in the `instrumentations` map in `CoralogixOptions`:

```
val options = CoralogixOptions(

    // ... other options ...

    instrumentations = mapOf(

        Instrumentation.Lifecycle to false

    )

)
```

### Automatic flush on backgrounding[​](#automatic-flush-on-backgrounding "Direct link to Automatic flush on backgrounding")

When the app moves to the background, the SDK immediately exports any events still held in its batch buffer, so telemetry from the end of a session is not lost if the process is killed while backgrounded. A WorkManager job is enqueued alongside it as a backstop, covering the case where the export does not finish before the system suspends the process.

This tracks the process-level background transition, so it fires once when the app actually leaves the foreground — not on activity-to-activity navigation within the app.

No configuration is required, and this is not tied to any instrumentation — it stays on even if you disable Lifecycle Events Reporting. You can also flush on demand at any point:

```
CoralogixRum.flush()



// Or, to react once the export completes:

CoralogixRum.flush {

    Log.d("MyApp", "buffered events exported")

}
```

### User Interaction Reporting[​](#user-interaction-reporting "Direct link to User Interaction Reporting")

Automatically tracks user interactions, including taps, scrolls, and swipes. Each event includes the target view, element class, and direction (where applicable).

#### Disabling this feature[​](#disabling-this-feature-6 "Direct link to Disabling this feature")

You can disable this instrumentation by passing `false` in the `instrumentations` map in `CoralogixOptions`:

```
val options = CoralogixOptions(

    // ... other options ...

    instrumentations = mapOf(

        Instrumentation.UserInteraction to false

    )

)
```

### Navigation Events Reporting[​](#navigation-events-reporting "Direct link to Navigation Events Reporting")

Automatically report any navigation event.

### Custom Spans[​](#custom-spans "Direct link to Custom Spans")

Create arbitrary OpenTelemetry spans that appear in the Coralogix RUM trace view. Spans are automatically linked to the current session and view context. Child spans inherit the parent's trace ID and carry a `parentSpanId`.

#### Prerequisites[​](#prerequisites "Direct link to Prerequisites")

Custom spans require W3C `traceparent` header injection to be enabled:

```
val options = CoralogixOptions(

    // ...

    traceParentInHeader = TraceParentInHeaderConfig(enabled = true)

)
```

`getCustomTracer()` returns `null` and logs a warning if this is not set.

#### Getting the tracer[​](#getting-the-tracer "Direct link to Getting the tracer")

```
val tracer = CoralogixRum.getCustomTracer() ?: return
```

* Returns `null` if the SDK is not initialized or `traceParentInHeader` is disabled.
* Only one tracer instance is issued per SDK lifecycle — subsequent calls return `null`. Store the returned instance and reuse it.
* Accepts an optional `ignoredInstruments` set to suppress specific automatic instrumentation while a global span is active (see [Ignored instruments](#ignored-instruments)).

#### Starting a global span[​](#starting-a-global-span "Direct link to Starting a global span")

A global span is the root of a custom trace. Only one global span can be active at a time.

```
val globalSpan = tracer.startGlobalSpan(

    name = "checkout-flow",

    labels = mapOf("cart.item_count" to 3)

) ?: return
```

* Returns `null` if a global span is already active.
* `labels` are optional. They are merged with the SDK-level labels and forwarded with every child span started from this global span.
* Exposes `traceId` and `spanId` properties (W3C hex strings) so you can correlate spans with your own backend:

```
val traceId: String = globalSpan.traceId   // 32 lowercase hex chars

val spanId: String  = globalSpan.spanId    // 16 lowercase hex chars
```

Always call `endSpan()` when the operation is complete:

```
globalSpan.endSpan()
```

#### Starting child spans[​](#starting-child-spans "Direct link to Starting child spans")

```
val childSpan = globalSpan.startCustomSpan(

    name = "payment-step",

    labels = mapOf("payment.method" to "credit_card")

)
```

* Child spans inherit the global span's trace ID and set the global span as their `parentSpanId`.
* `labels` are optional and are merged with SDK labels and the global span's labels.
* Always call `endSpan()` when the child operation is complete:

```
childSpan.endSpan()
```

#### Setting attributes[​](#setting-attributes "Direct link to Setting attributes")

`CoralogixCustomSpan` supports four attribute types:

```
childSpan.setAttribute("http.method",   "GET")       // String

childSpan.setAttribute("http.status",   200)         // Int

childSpan.setAttribute("duration.ms",   3.14)        // Double

childSpan.setAttribute("from.cache",    true)        // Boolean
```

#### Adding events[​](#adding-events "Direct link to Adding events")

Add timestamped events to a span to record notable moments during its lifetime.

```
// Event with no extra data

childSpan.addEvent("retry-attempted")



// Event with attributes

childSpan.addEvent(

    name = "cache-miss",

    attributes = mapOf("key" to "user-profile", "size_bytes" to 1024)

)



// Event at a specific time (defaults to milliseconds)

childSpan.addEvent(

    name = "request-sent",

    timestamp = System.currentTimeMillis() - 500,

    unit = TimeUnit.MILLISECONDS

)



// Event with both attributes and a custom timestamp

childSpan.addEvent(

    name = "response-received",

    attributes = mapOf("status" to "200"),

    timestamp = System.currentTimeMillis(),

    unit = TimeUnit.MILLISECONDS

)
```

Supported attribute value types: `String`, `Int`, `Long`, `Double`, `Float`, `Boolean`. Any other type (including `null`) is silently ignored.

#### Setting span status[​](#setting-span-status "Direct link to Setting span status")

```
childSpan.setStatus(StatusCode.OK)

childSpan.setStatus(StatusCode.ERROR)
```

#### Cross-thread context propagation[​](#cross-thread-context-propagation "Direct link to Cross-thread context propagation")

If you start a child span from a different thread than the global span, use `withContext` to make the global span the active OTel context on that thread:

```
globalSpan.withContext {

    val childSpan = globalSpan.startCustomSpan("background-task")

    // ... do work ...

    childSpan.endSpan()

}
```

#### Complete example[​](#complete-example "Direct link to Complete example")

```
val tracer = CoralogixRum.getCustomTracer() ?: return



val globalSpan = tracer.startGlobalSpan(

    name = "checkout-flow",

    labels = mapOf("cart.item_count" to 3)

) ?: return



val paymentSpan = globalSpan.startCustomSpan(

    name = "payment-step",

    labels = mapOf("payment.method" to "credit_card")

)



paymentSpan.addEvent("payment-initiated")



try {

    processPayment()

    paymentSpan.setAttribute("payment.success", true)

    paymentSpan.setStatus(StatusCode.OK)

    paymentSpan.addEvent("payment-complete")

} catch (e: Exception) {

    paymentSpan.setAttribute("error.message", e.message ?: "unknown")

    paymentSpan.setStatus(StatusCode.ERROR)

} finally {

    paymentSpan.endSpan()

    globalSpan.endSpan()

}
```

#### Ignored instruments[​](#ignored-instruments "Direct link to Ignored instruments")

Pass `ignoredInstruments` to `getCustomTracer()` to prevent specific automatic instrumentation from firing while a global span is active:

```
val tracer = CoralogixRum.getCustomTracer(

    ignoredInstruments = setOf(

        CoralogixIgnoredInstrument.NETWORK_REQUESTS,

        CoralogixIgnoredInstrument.USER_INTERACTIONS,

        CoralogixIgnoredInstrument.ERRORS

    )

) ?: return
```

| Value               | Description                                            |
| ------------------- | ------------------------------------------------------ |
| `NETWORK_REQUESTS`  | Suppresses automatic network event reporting.          |
| `USER_INTERACTIONS` | Suppresses automatic user-interaction event reporting. |
| `ERRORS`            | Suppresses automatic error/crash event reporting.      |

#### Receiving raw OTLP span data (`tracesExporter`)[​](#receiving-raw-otlp-span-data-tracesexporter "Direct link to receiving-raw-otlp-span-data-tracesexporter")

Supply a `tracesExporter` callback in `CoralogixOptions` to receive the raw OTLP payload for each batch of exported spans — useful for forwarding to a backend trace collector:

```
val options = CoralogixOptions(

    // ...

    tracesExporter = { data: CoralogixTraceExporterData ->

        val spanCount = data.spanCount          // total spans in this batch

        val json      = data.toJson()               // full OTLP JSON string

        val spans     = data.resourceSpans      // structured List<OtlpResourceSpans>



        forwardToMyCollector(json)

    }

)
```

`CoralogixTraceExporterData` fields:

| Field           | Type                      | Description                                      |
| --------------- | ------------------------- | ------------------------------------------------ |
| `resourceSpans` | `List<OtlpResourceSpans>` | Structured OTLP resource-spans tree.             |
| `spanCount`     | `Int`                     | Total number of spans across all resource-spans. |

`CoralogixTraceExporterData` exposes `toJson()` for convenience, returns the full OTLP JSON encoding of this batch (ready to POST).

Note

When `tracesExporter` is set, `instrumentation_data` (network request details) is stripped from the standard RUM payload to avoid double-reporting.
