The Honeycomb OpenTelemetry Android SDK is Honeycomb’s OpenTelemetry Android distribution. It simplifies adding instrumentation to your Android applications and sending telemetry to Honeycomb.
This page briefly covers usage of the SDK. If you just want to see some code, check out the examples on GitHub.
Before you can add instrumentation to your Android application, you will need to do a few things.
To send data to Honeycomb, you need to:
Sign up for a Honeycomb account. To sign up, decide whether you would like Honeycomb to store your data in a US-based or EU-based location, then create a Honeycomb account in the US or create a Honeycomb account in the EU.
Create a Honeycomb Ingest API Key. To get started, you can create a key that you expect to swap out when you deploy to production. Name it something helpful, perhaps noting that it’s a Getting Started key. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later!
Add the Honeycomb and OpenTelemetry Android SDKs to your application’s build.gradle.kts
.
When adding OpenTelemetry dependencies, make sure the library is compatible with the Honeycomb Android SDK.
dependencies {
implementation("io.opentelemetry.android:android-agent:0.11.0-alpha")
implementation("io.honeycomb.android:honeycomb-opentelemetry-android:0.0.10")
}
If your application’s minSDK
is lower than 26, enable corelib desugaring:
android {
// ...
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
coreLibraryDesugaring(libs.desugar.jdk.libs)
}
If your application’s minSdk
is lower than 24, running instrumentation tests or debug application builds requires that you:
android.useFullClasspathForDexingTransform=true
to your gradle.properties
.Option | Description |
---|---|
apiKey | String Your Honeycomb Ingest API Key. Required if sending telemetry directly to Honeycomb. |
tracesApiKey | String Ingest API Key to use when sending traces. Overrides apiKey for traces. |
metricsApiKey | String Ingest API Key to use when sending metrics. Overrides apiKey for metrics. |
logsApiKey | String Ingest API Key to use when sending logs. Overrides apiKey for logs. |
dataset | String Name of the dataset to send telemetry data to. Required if using Honeycomb Classic. |
metricsDataset | String Name of the dataset to send metrics to. Overrides dataset for metrics. |
apiEndpoint | String Telemetry is sent to this URL. For Honeycomb EU instances, set this to https://api.eu1.honeycomb.io:443 . If you’re using an OpenTelemetry Collector, provide your collector URL instead.Default: https://api.honeycomb.io:443 (US instance) |
tracesEndpoint | String API endpoint to send traces to. |
metricsEndpoint | String API endpoint to send metrics to. |
logsEndpoint | String API endpoint to send logs to. |
spanProcessor | io.opentelemetry.sdk.trace.SpanProcessor Additional span processor to use. |
sampleRate | Int Sample rate to apply. For example, a sampleRate of 40 means 1 in 40 traces will be exported.Default: 1 |
debug | Boolean Whether to enable debug logging. Default: false . |
serviceName | String The name of your application. Used as the value for service.name resource attribute. Default: "unknown_service" |
serviceVersion | String Current version of your application. Used as the value for service.version resource attribute. |
resourceAttributes | Map<String, String> Attributes to attach to outgoing resources. |
headers | Map<String, String> Headers to add to exported telemetry data. |
tracesHeaders | Map<String, String> Headers to add to exported trace data. |
metricsHeaders | Map<String, String> Headers to add to exported metrics data. |
logsHeaders | Map<String, String> Headers to add to exported logs data. |
timeout | Duration Timeout used by exporter when sending data. Default: Duration = 10.seconds |
tracesTimeout | Duration Timeout used by traces exporter. Overrides timeout for trace data. |
metricsTimeout | Duration Timeout used by metrics exporter. Overrides timeout for metrics data. |
logsTimeout | Duration Timeout used by logs exporter. Overrides timeout for logs data. |
protocol | OtlpProtocol Protocol to use when sending data. Can be one of: OtlpProtocol.GRPC , OtlpProtocol.HTTP_PROTOBUF , OtlpProtocol.HTTP_JSON .Default: OtlpProtocol.HTTP_PROTOBUF |
tracesProtocol | OtlpProtocol Overrides protocol for trace data. |
metricsProtocol | OtlpProtocol Overrides protocol for metrics data. |
logsProtocol | OtlpProtocol Overrides protocol for logs data. |
offlineCachingEnabled | Boolean Enable offline caching for telemetry. When offline caching is enabled, telemetry is cached during network failures. The SDK will retry exporting telemetry for up to 18 hours. Offline caching also adds a minimum delay of 30 seconds to telemetry exports. Offline caching is an alpha feature and may be unstable. Default: false |
Resource attributes are available on every span your instrumentation emits. Adding custom, application-specific attributes makes it easier to correlate your data to important business information.
You can add extra resource attributes during SDK configuration with the .setResourceAttributes()
method.
import android.app.Application
import io.honeycomb.opentelemetry.android.Honeycomb
import io.honeycomb.opentelemetry.android.HoneycombOptions
import io.opentelemetry.android.OpenTelemetryRum
class ExampleApp: Application() {
var otelRum: OpenTelemetryRum? = null
override fun onCreate() {
super.onCreate()
val options = HoneycombOptions.builder(this)
.setApiKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
.setServiceVersion("0.0.1")
.setResourceAttributes(mapOf("app.ab_test" to "test c"))
.setDebug(true)
.build()
otelRum = Honeycomb.configure(this, options)
}
}
The Honeycomb Android SDK includes optional deterministic head sampling.
To enable sampling, call .setSampleRate()
with your desired sample rate as an Int
value.
The sample rate is 1
by default, meaning every trace is exported.
The example below sets a sampleRate
of 40
, meaning 1 in 40 traces will be exported.
// ...
val options = HoneycombOptions.Builder(this)
.setApiKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
.setServiceVersion("0.0.1")
.setSampleRate(40)
.setDebug(true)
.build()
// ...
Enable all OpenTelemetry auto-instrumentations by including the OpenTelemetry android-agent:
dependencies {
implementation("io.opentelemetry.android:android-agent:0.11.0")
implementation("io.honeycomb.android:honeycomb-opentelemetry-android:0.0.9")
}
If you don’t need all of them, you can instead add dependencies for each instrumentation you want to include:
io.opentelemetry.android:instrumentation-activity
io.opentelemetry.android:instrumentation-anr
io.opentelemetry.android:instrumentation-crash
io.opentelemetry.android:instrumentation-fragment
io.opentelemetry.android:instrumentation-slowrendering
Automatic instrumentation is a fast way to instrument your code, but you get more insight into your application by adding custom, or manual, instrumentation.
To add your own custom instrumentation, import the OpenTelemetry API in to your application.
import io.opentelemetry.api.OpenTelemetry
You can retrieve the currently active span in a trace and add attributes to it. This lets you add more context to traces and gives you more ways to group or filter traces in your queries:
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.common.Attributes
fun applyDiscountCode(discountCode: String) {
val currentSpan = Span.current()
currentSpan.setAttribute("app.cart.discount_code", discountCode)
}
In the above example, we add an app.cart.discount_code
attribute to the current span.
This lets us use the app.cart.discount_code
field in WHERE
or GROUP BY
clauses in the Honeycomb query builder.
To create custom spans, you need to acquire a tracer:
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.android.OpenTelemetryRum
// ...
val otelRum = app.otelRum as OpenTelemetryRum
val tracer = otelRum.tracerProvider.tracerBuilder("my-application-tracer").build()
Create custom spans to get a clear view of the critical parts in your application.
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.common.Attributes
import io.opentelemetry.android.OpenTelemetryRum
// ...
val otelRum = app.otelRum as OpenTelemetryRum
val tracer = otelRum.tracerProvider.tracerBuilder("my-application-tracer").build()
fun generateNewLevel() {
val span = tracer.spanBuilder("newLevel").startSpan()
// do some work
span.end()
}
Span processors provide hooks for when a span starts and when it ends. This lets you mutate spans after they have been created by automatic or manual instrumentation.
Here’s a basic example of a span processor that adds an attribute to spans when they start:
import io.opentelemetry.context.Context
import io.opentelemetry.sdk.trace.ReadWriteSpan
import io.opentelemetry.sdk.trace.ReadableSpan
import io.opentelemetry.sdk.trace.SpanProcessor
class BasicSpanProcessor : SpanProcessor {
override fun onStart(
parentContext: Context,
span: ReadWriteSpan,
) {
span.setAttribute("app.metadata", "extra metadata")
}
override fun isStartRequired(): Boolean {
return true
}
override fun onEnd(span: ReadableSpan) {}
override fun isEndRequired(): Boolean {
return false
}
}
Add the span processor as part of your SDK configuration to use it:
// ...
val options = HoneycombOptions.builder(this)
.setApiKey("YOUR-API-KEY")
.setServiceName("YOUR-SERVICE-NAME")
.setSpanProcessor(BasicSpanProcessor())
.setServiceVersion("0.0.1")
.setDebug(true)
.build()
// ...
Kotlin Coroutines may operate across multiple threads, and do not automatically inherit the correct OpenTelemetry context.
Instead, context must be propagated manually with the OpenTelemetry Kotlin Extensions.
dependencies {
implementation("io.opentelemetry:opentelemetry-extension-kotlin:1.47.0")
}
Once these are installed, replace any launch
calls with
launch(Span.current().asContextElement()) {
// ...
}
To explore common issues when sending data, visit Common Issues with Sending Data in Honeycomb.