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
Test the sample app for Kotlin.
Step 1: Add OpenTelemetry dependencies
Add these to your module 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:
<?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:
<?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:
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 exampleus,eu, orin.<your-ingestion-key>: ingestion key for your SigNoz Cloud organization.
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:
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.api.trace.Span
import io.opentelemetry.context.Scope
Create spans:
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.cloudor your self-hosted collector endpoint is reachable from the emulator/device and that the ingestion key (for Cloud) is correct.
Next steps
- Explore your mobile traces in the Trace Explorer.
- Create latency and error alerts for your service using Alert Management.