Skip to main content

Supported instrumentations

Supported Instrumentations

InstrumentationDescription
LogsStructured logging with severity and labels (called Custom)
ErrorsUncaught & handled exceptions
NetworkRequest/response performance data
ANRANR tracking
Mobile VitalsCPU, FPS, memory, and cold/warm start times.
Custom MetricsUser-defined numeric metrics
LifecycleReport lifecycle events.
User InteractionReport user interactions in the application.
NavigationReport navigation events

Logs (Custom)

Send a simple log with optional data and labels.

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

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

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

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

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

Example
try {
riskyOperation()
} catch (t: Throwable) {
CoralogixRum.reportError(t)
}
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

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

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

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

Examples

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
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
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

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

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

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

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

CategoryMetricDescription
Frame RenderingFPS (Frames Per Second)Measures how smoothly your app renders frames. Low FPS indicates UI stutters or heavy rendering work.
Frame QualitySlow Frames / Frozen FramesTracks frames that exceeded normal rendering budgets (slow) or were completely stuck (frozen).
CPU UsageTotal / Main Thread CPUCaptures overall and main-thread CPU usage percentage and timing, helping identify CPU-heavy operations.
Memory UsageResident / Heap / Java / Native MemoryTracks memory utilization from both Java and native layers to identify leaks or memory pressure.
Startup PerformanceCold Start / Warm Start TimeMeasures how long it takes for the app to become ready when launched cold or resumed from background.

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

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

EventDescription
Cold StartTime taken from process creation until the first activity is visible.
Warm StartTime 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

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

Send arbitrary key-value pairs.

Example

CoralogixRum.sendCustomMeasurement("image_upload_time_ms", 1480L)

Custom Time Measurement

Measure the elapsed time of any operation.

Example

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

See the Custom Time Measurement section in the API Reference for full behaviour details.

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

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

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

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

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
)
)

Automatically report any navigation event.

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

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

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).

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

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

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

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

childSpan.setStatus(StatusCode.OK)
childSpan.setStatus(StatusCode.ERROR)

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

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

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
ValueDescription
NETWORK_REQUESTSSuppresses automatic network event reporting.
USER_INTERACTIONSSuppresses automatic user-interaction event reporting.
ERRORSSuppresses automatic error/crash event reporting.

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:

FieldTypeDescription
resourceSpansList<OtlpResourceSpans>Structured OTLP resource-spans tree.
spanCountIntTotal 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.

Last updated on