Honeycomb wrapper for OpenTelemetry on Android.
STATUS: this library is EXPERIMENTAL. Data shapes are unstable and not safe for production. We are actively seeking feedback to ensure usability.
Add the following dependencies to your build.gradle.kts
:
dependencies {
implementation("io.honeycomb.android:honeycomb-opentelemetry-android:0.0.4-alpha")
}
To configure the SDK in your Application class:
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")
.build()
otelRum = Honeycomb.configure(this, options)
}
}
To manually send a span:
val app = application as ExampleApp
val otelRum = app.otelRum
val otel = otelRum?.openTelemetryA
val tracer = otel?.getTracer("YOUR-INSTRUMENTATION-NAME")
val span = tracer?.spanBuilder("YOUR-SPAN-NAME")?.startSpan()
span?.end()
Option | Type | Required? | Description |
---|---|---|---|
apiKey |
String | Yes | Default Honeycomb API Key to use to send data directly to Honeycomb. |
tracesApiKey |
String | No | Dedicated API Key to use when sending traces. |
metricsApiKey |
String | No | Dedicated API Key to use when sending metrics. |
logsApiKey |
String | No | Dedicated API Key to use when sending logs. |
dataset |
String | No | Name of Honeycomb dataset to send traces to. Required if sending to a classic Honeycomb environment. |
metricsDataset |
String | No | Name of Honeycomb dataset to send metrics to, instead of dataset . |
apiEndpoint |
String | No | API endpoint to send data to. |
tracesEndpoint |
String | No | API endpoint to send traces to. Overrides apiEndpoint for trace data. |
metricsEndpoint |
String | No | API endpoint to send metrics to. Overrides apiEndpoint for metrics data. |
logsEndpoint |
String | No | API endpoint to send trace to. Overrides apiEndpoint for logs data. |
sampleRate |
Int | No | Sample rate to apply (ie. a value of 40 means 1 in 40 traces will be exported). |
debug |
Boolean | No | Enable debug logging. |
serviceName |
String? | No | Name of Honeycomb service to send data to. |
resourceAttributes |
Map<String, String> | No | Attributes to attach to outgoing resources. |
headers |
Map<String, String> | No | Headers to include on exported data. |
tracesHeaders |
Map<String, String> | No | Headers to add to exported trace data. |
metricsHeaders |
Map<String, String> | No | Headers to add to exported metrics data. |
logsHeaders |
Map<String, String> | No | Headers to add to exported logs data. |
timeout |
Duration | No | Timeout used by exporter when sending data. |
tracesTimeout |
Duration | No | Timeout used by traces exporter. Overrides timeout for trace data. |
metricsTimeout |
Duration | No | Timeout used by metrics exporter. Overrides timeout for metrics data. |
logsTimeout |
Duration | No | Timeout used by logs exporter. Overrides timeout for logs data. |
protocol |
io.honeycomb.opentelemetry.android.OtlpProtocol | No | Protocol to use when sending data. |
tracesProtocol |
io.honeycomb.opentelemetry.android.OtlpProtocol | No | Overrides protocol for trace data. |
metricsProtocol |
io.honeycomb.opentelemetry.android.OtlpProtocol | No | Overrides protocol for metrics data. |
logsProtocol |
io.honeycomb.opentelemetry.android.OtlpProtocol | No | Overrides protocol for logs data. |
The following auto-instrumentation libraries are automatically included:
io.opentelemetry.android:android-agent
io.opentelemetry.android:instrumentation-activity
io.opentelemetry.android:instrumentation-anr
io.opentelemetry.android:instrumentation-crash
io.opentelemetry.android:instrumentation-slowrendering
The following additional auto-instrumentation is implemented in this library:
- UI interaction in XML-based Activities.
A trace is emitted before, during, and after each stage of the Android Activity Lifecycle.
- AppStart
- name:
AppStart
- attributes:
start.type
:"hot"
or"cold"
- name:
- Created
- name:
Created
- events:
activityPreCreated
,activityCreated
,activityPostCreated
activityPreStarted
,activityStarted
,activityPostStarted
activityPreResumed
,activityResumed
,activityPostResumed
- name:
- Paused
- name:
Paused
- events:
activityPrePaused
,activityPaused
,activityPostPaused
- name:
- Stopped
- name:
Stopped
- events:
activityPreStopped
,activityStopped
,activityPostStopped
- name:
- Destroyed
- name:
Destroyed
- events:
activityPreDestroyed
,activityDestroyed
,activityPostDestroyed
- name:
activityName
- The unqualified name for the activity, such as"MainActivity"
A trace is emitted whenever the app becomes unresponsive for longer than approximately 5 seconds (ANR).
- name:
ANR
- attributes:
exception.stacktrace
A trace is emitted whenever an uncaught exception is going to terminate the program. This is in addition to whatever other crash reporting is enabled. These traces are flushed as the app is shutting down, so the app does not need to be re-opened for them to be sent.
- name:
UncaughtException
- attributes:
exception.name
exception.message
exception.stacktrace
exception.escaped
thread.name
thread.id
A trace is emitted whenever a frame is rendered too slowly, according to Android's Slow rendering guidelines.
- name:
slowRenders
(>16ms) orfrozenRenders
(>700ms) - attributes:
activity.name
- the fully-qualified name of the activity, such as"io.honeycomb.opentelemetry.android.example/.MainActivity"
Network instrumentation is not included by default but can be configured on top of this distro. We test with the following OpenTelemetry instrumentation packages:
Configuration of each of these packages is described in their respective READMEs.
Various touch events are instrumented for TextView
fields, such as:
Touch Began
- A touch startedTouch Ended
- A touch endedclick
- A "tap"
These events may have the following attributes.
view.class
- e.g."android.widget.Button"
view.accessibilityClassName
- TheaccessibilityClassName
for the view. Usually the same asview.class
.view.text
- The text of theTextView
.view.id
- The XML ID of the view element, as an integer.view.id.entry
- The text form of the XML ID of the view element.view.id.package
- The package for the XML ID of the view.view.name
- The "best" available name of the view, given the other identifiers. Usually the same asview.id.entry
.
In most cases, OpenTelemetry context will be propagated correctly across function calls, etc. By default, OpenTelemetry context is stored in a java.lang.ThreadLocal
. However, Kotlin Coroutines may operate across multiple threads, and therefore do not automatically inherit the correct OpenTelemetry context.
Instead, context must be propagated manually, via 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()) {
}
Android Compose instrumentation is included in a standalone library. Add the following to your dependencies in build.gradle.kts
:
dependencies {
implementation("io.honeycomb.android:honeycomb-opentelemetry-android-compose:0.0.3-alpha")
}
After you initialize the Honeycomb
sdk, wrap your entire app in a CompositionLocalProvider
that provides LocalOpenTelemetryRum
, as so:
import io.honeycomb.opentelemetry.android.compose.LocalOpenTelemetryRum
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val app = application as ExampleApp
val otelRum = app.otelRum
setContent {
CompositionLocalProvider(LocalOpenTelemetryRum provides otelRum) {
// app content
}
}
}
}
Wrap your Composables with HoneycombInstrumentedComposable(name: String)
, like so:
@Composable
private fun MyComposable() {
HoneycombInstrumentedComposable("main view") {
// ...
}
}
This will measure and emit instrumentation for your Composable's render times, ex:
Specifically, it will emit 2 kinds of span for each composable that is wrapped:
View Render
spans encompass the entire rendering process, from initialization to appearing on screen. They include the following attributes:
view.name
(string): the name passed toHoneycombInstrumentedComposable
view.renderDuration
(double): amount of time in seconds to spent initializing the contents ofHoneycombInstrumentedComposable
view.totalDuration
(double): amount of time in seconds from when the contents ofHoneycombInstrumentedComposable
start initializing to when the contents appear on screen
View Body
spans encompass just the contents of the HoneycombInstrumentedView
, and include the following attributes:
view.name
(string): the name passed toHoneycombInstrumentedComposable