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
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/src/main/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.SERVICE_VERSION, "<service_version>",
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
}
}
}Verify these values:
<service_name>: logical name of your mobile service; this is what you will see in SigNoz.<service_version>(optional): Your release version, image tag, or git SHA (e.g.,1.4.2,a01dbef8).<region>: Your SigNoz Cloud region<your-ingestion-key>: Your SigNoz ingestion key
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.ScopeCreate 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
Still not seeing data in SigNoz? Work through Debug missing traces, logs, and metrics, which covers SDK diagnostics, Collector connectivity, and the common ingestion errors for all three signals.
- 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.