Embrace’s iOS and Android SDKs are now built on OpenTelemetry!

Read the release
Open Source

Android OpenTelemetry exporter walkthrough

Learn how to use Embrace's OpenTelemetry SDK distribution to instrument traces in your app and export them to an observability backend.

Welcome to our spans exporter tutorial for Android! If you’ve landed here, you likely know that Embrace recently released our Android OpenTelemetry SDK, which is open sourced on GitHub. The new release will let you leverage Embrace’s technology to capture data indicative of any performance issues affecting your app.

Now that our SDKs are OpenTelemetry-complaint, they have the major benefits of:

(1) being fully extensible, so you can broaden the instrumentation to customize the data you want to capture, including collecting telemetry from 3rd-party libraries.

(2) being interoperable with many other open source tools in the OpenTelemetry orbit, which means you can very easily forward your data to where you want to view and analyze it.

Since our SDKs are also open source, you can collect and forward your mobile telemetry data to another service without being a paid Embrace user. 

In this tutorial, we’ll show you how to do this for a powerful OpenTelemetry data type – traces (and spans).

We’ll guide you through the steps to instrument and collect OpenTelemetry spans from your app via Embrace’s Android SDK, and then how to send those traces from your interconnected spans on to a generic exporter. 

You can also learn more from our video tutorials on OTel signal instrumentation here.

If you’re an iOS developer, head over to our iOS tutorials for OpenTelemetry.

Step 1: Load and apply the Embrace Android SDK

As a prerequisite for the rest of this tutorial, you’ll need to integrate the Embrace SDK. If you’ve already done so, feel free to skip ahead to step 2. If not, follow these instructions on how to get set up with the SDK first. 

Let’s now grab the open source Embrace SDK and import it into our project. You can find the repo here

To get started using the Embrace SDK, you’ll need to first update your settings.gradle:

pluginManagement {
    repositories {
        mavenCentral()
    }
    val swazzler_version: String by settings
    plugins {
        id("io.embrace.swazzler") version "${swazzler_version}" apple false
    }

and be sure to define swazzler_version as the latest version in gradle.properties

swazzler_version=6.6.0

    Finally, in app/build.gradle, apply the plugin:

    plugins {
        id("io.embrace.swazzler")
    }

    If you are having difficulty, be sure to check out the documentation for adding Embrace as a dependency.

    Step 2: Attaching an OpenTelemetry exporter

    Before we begin the Embrace Android SDK, we can add one or multiple exporters to give a destination for our traces once that data is actually generated. 

    The exporter is a component that will connect the Embrace SDK, which will collect the traces and spans, with an external OpenTelemetry collector that will receive the data.

    Note: In the Embrace Android SDK, you must add all exporters before starting the SDK

    2A: Download the exporter

    You don’t have to build an exporter yourself as there are a few open source options available to you. For this example, we’ll be using the OpenTelemetry Zipkin exporter for Java . This will let the Embrace SDK send your traces and spans data to Zipkin, an observability backend that lets you visualize your data nicely.

    2B: Attach the Zipkin exporter object 

    The exporter object provides the interface for the Embrace SDK to send our traces and spans to an exporter. By default, the Embrace SDK won’t send telemetry anywhere, but you can tell it to do that by attaching an exporter object. The parameter can be either a collector location, or an endpoint for an observability backend.

    If we wanted to export to an OTel Collector running locally via HTTP, we could build the following exporter:

    val customLocalExporter = OtlpHttpSpanExporter.builder()
        .setEndpoint("http://10.0.2.2:4318")

    With a Zipkin image running locally, we can build the exporter from the OpenTelemetry-Java link above. The ports are pre-configured for the ZipkinSpanExporter (port 9411), so you shouldn’t need to change any settings.

    val zipkinLocalExporter = ZipkinSpanExporter.build()

     

    In both cases, we’ll add the exporter to the Embrace client instance before going any further

    Embrace.getInstance().addSpanExporter(customLocalExporter)
    Embrace.getInstance().addSpanExporter(zipkinLocalExporter)

     

    Step 3: Start the Embrace SDK

    Prior to any instrumentation, but after adding all exporters, you should start the Embrace Android SDK:

    Embrace.getInstance().start(this)

    Step 4: Instrument your trace

    Now that we’ve got the exporter and its destination set up, we can back into our source code and instrument some spans. 

    If you’re not familiar with spans and traces, they allow you to observe flows or transaction in your app (trace) by breaking it up into its component operations (spans). You’ll know you should use traces and spans if you want to observe a process over time by collecting the steps that complete that process.

    For example, a trace might be taking a dog for a walk, and the spans or “units of work” that make up that trace might be finding one’s shoes, picking up waste, and returning home.

    Let’s define our trace around the walk, as follows:

    val walkTrace = Embrace.getInstance().startSpan("Afternoon Walk")

    The .startSpan call both creates the span, and starts it beginning right now.

    Step 5: Add child spans

    Spans can have parent-child relationships, which can be helpful in building and understanding hierarchy. Let’s add a child span to the walk trace we’ve already instrumented, making that original span a parent:

    val findShoesSpan = walkTrace?.let {
        Embrace.getInstance().startSpan("Find Leash", it) 
    }

     

    Child spans can also have child spans, creating a hierarchy from the root trace. This is because units of work can themselves usually be broken down into smaller units.

    Step 6: Add span events and attributes

    We can give our spans even more context by adding attributes and events. Attributes are represented by key-value pairs, while events record a point-in-time condition.

    If your walk brought you to Golden Gate Park, your parent trace might have an attribute key of “walk-location” with the value “park”:

    walkTrace?.addAttribute("walk-location", "park")

    Your dog might also be overly-insistent while you look for your shoes, and you’ll want to document this event to report back to your trainer

    findShoesSpan?.addEvent("Barked and misbehaved")

    Step 7: Spans must be stopped

    For spans to be completed and exported, they must be stopped in the client instrumentation. The Embrace SDKs have no automatic instrumentation to end a span if device changes occur, as span ends must be defined.

    // stop span
    walkTrace?.stop()
    
    // stop span with failure
    walkTrace?.stop(ErrorCode.FAILURE)
    

    Step 8: Run your app

    Run your sample app a few times to generate some data. 

    Step 9: View your traces and spans in the observability backend

    In step 2, we set up an exporter to send our spans to Zipkin. No further configuration is required to connect the SDK to the Zipkin instance. Now that we’ve run the app a few times, let’s check out the Zipkin UI and see if the data was indeed captured.

    Success! We’ve integrated the Embrace Android SDK, set up an exporter to connect the application to Zipkin, instrumented our spans, and now are able to view them as traces in this tracing system. Full mobile-client instrumentation is available in our OpenTelemetry SDK, even if you don’t want to use Embrace as your backend.

    Embrace Deliver incredible mobile experiences with Embrace.

    Get started today with 1 million free user sessions.

    Get started free

    Build better mobile apps with Embrace

    Find out how Embrace helps engineers identify, prioritize, and resolve app issues with ease.