SigNoz Cloud - This page is relevant for SigNoz Cloud editions.
Self-Host - This page is relevant for self-hosted SigNoz editions.

Android app in Kotlin instrumentation

Overview

This document contains instructions on how to set up OpenTelemetry instrumentation in your Android applications built using Kotlin and view your application traces in SigNoz.

Prerequisites

  • Kotlin support in your Android app project.
  • Kotlin toolchain installed; see the Kotlin documentation.
  • Access to a SigNoz Cloud account or self-hosted SigNoz instance.

Send traces to SigNoz

📝 Note

Test the sample app for Kotlin.

Step 1: Add OpenTelemetry dependencies

Add these to your module build.gradle:

app/build.gradle
implementation platform("io.opentelemetry:opentelemetry-bom:1.25.0")
implementation("io.opentelemetry:opentelemetry-api")
implementation("io.opentelemetry:opentelemetry-context")
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
implementation("io.opentelemetry:opentelemetry-exporter-logging")
implementation("io.opentelemetry:opentelemetry-extension-kotlin")
implementation("io.opentelemetry:opentelemetry-sdk")
implementation("io.opentelemetry:opentelemetry-semconv")

Step 2: Configure network settings

app/res/xml/network_security_config.xml:

app/res/xml/network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">ingest.<region>.signoz.cloud</domain>
    </domain-config>
</network-security-config>

app/src/main/AndroidManifest.xml:

app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
  <uses-permission android:name="android.permission.INTERNET" />

  <application
    ...
    android:networkSecurityConfig="@xml/network_security_config">
    ...
  </application>

</manifest>

For self-hosted, replace the domain with your collector host (emulator often 10.0.2.2). Allow cleartext only when you use http://.

Step 3: Initialize OpenTelemetry

Create OpentelemetryUtil.kt:

app/src/main/java/com/example/androidkotlindemo/OpenTelemetryUtil.kt
package com.example.androidkotlindemo

import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.common.Attributes
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator
import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.exporter.logging.LoggingSpanExporter
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter
import io.opentelemetry.sdk.OpenTelemetrySdk
import io.opentelemetry.sdk.resources.Resource
import io.opentelemetry.sdk.trace.SdkTracerProvider
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes

class OpenTelemetryUtil {
    companion object {
        @JvmStatic
        fun init() {
            val otelResource = Resource.getDefault().merge(
                Resource.create(
                    Attributes.of(
                        ResourceAttributes.SERVICE_NAME, "<service_name>",
                        ResourceAttributes.HOST_NAME, "<service_name>"
                    )
                )
            )

            val sdkTracerProvider = SdkTracerProvider.builder()
                .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create()))
                .addSpanProcessor(
                    BatchSpanProcessor.builder(
                        OtlpGrpcSpanExporter.builder()
                            .setEndpoint("ingest.<region>.signoz.cloud:443/v1/traces")
                            .addHeader("signoz-ingestion-key", "<your-ingestion-key>")
                            .build()
                    ).build()
                )
                .setResource(otelResource)
                .build()

            val openTelemetry: OpenTelemetry = OpenTelemetrySdk.builder()
                .setTracerProvider(sdkTracerProvider)
                .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
                .buildAndRegisterGlobal()

            tracer = openTelemetry.getTracer("android-tracer", "1.0.0")
        }

        private var tracer: Tracer? = null

        @JvmStatic
        fun getTracer(): Tracer? {
            return tracer
        }
    }
}

Replace the placeholders:

  • <service_name>: logical name of your mobile service; this is what you will see in SigNoz.
  • <region>: your SigNoz Cloud region, for example us, eu, or in.
  • <your-ingestion-key>: ingestion key for your SigNoz Cloud organization.
Info

Using self-hosted SigNoz? Most steps are identical. Update the endpoint and remove the ingestion key header as shown in Cloud → Self-Hosted.

Initialize OpenTelemetry in MainActivity.kt:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        OpenTelemetryUtil.init()
        ...
    }
}

Step 4: Send telemetry data

Add the tracer imports where you create spans:

app/src/main/java/com/example/androidkotlindemo/MainActivity.kt
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.api.trace.Span
import io.opentelemetry.context.Scope

Create spans:

app/src/main/java/com/example/androidkotlindemo/MainActivity.kt
fun parentSpan() {
    val tracer: Tracer = OpenTelemetryUtil.getTracer()!!
    val span = tracer.spanBuilder("Parent Span").startSpan()
    try {
        span.makeCurrent().use {
            childSpan()
        }
    } finally {
        span.end()
    }
}

fun childSpan() {
    val tracer: Tracer = OpenTelemetryUtil.getTracer()!!
    val span = tracer.spanBuilder("Child Span").startSpan()
    try {
        span.makeCurrent().use {
            // add attributes/events as needed
        }
    } finally {
        span.end()
    }
}

Step 5: Run the app

Run your application from Android Studio.

Validate

  • In SigNoz, go to Traces Explorer and confirm that the traces for your service (for example <service_name>) are present.
  • Open a recent trace and verify that spans from your Kotlin Android app are present with the attributes you set.

Troubleshooting

  • If spans are missing, verify that the ingest.<region>.signoz.cloud or your self-hosted collector endpoint is reachable from the emulator/device and that the ingestion key (for Cloud) is correct.

Next steps

Last updated: November 22, 2025

Edit on GitHub

Was this page helpful?