Open Source

Embrace’s iOS SDK is built on OTel, but what does this mean?

Embrace’s open source Swift SDK was re-architected from its foundations to use OpenTelemetry conventions and signals.

Embrace is now OTel-compliant in our iOS and Android SDKs. In practice, this means that all the instrumentation you’ve come to expect from Embrace is provided as OTel signals. How did we do it? The two SDKs took very different routes to get there, so here let’s take a look at the iOS approach.

Rebuilding our signals

The iOS SDK builds OTel traces and logs right into each signal that you send. Previous iOS versions were driven by app events, such as taps, network requests, or memory warnings. Now, in fitting with the OTel specification, we rewrote the SDK so that the events could be captured with a duration (traces/spans) or duration-irrelevant signals (logs).

When instrumenting the app yourself, for example, using Performance Tracing, you can call a buildSpan method that creates a SpanBuilder object that will report spans to our backend as well as any OTel collectors.

First, in buildSpan, you can see this calls an OTel-wrapping function further down the chain:

//in Sources/EmbraceCode/Public/Embrace+OTel.swift
private var otel: EmbraceOTel { EmbraceOTel() }

//farther down...
public func buildSpan(
    name: String, 
    type: SpanType, 
    attributes: [String: String]
){
    otel.buildSpan(name: name, type: type, attributes: attributes)
}

What is that `otel` wrapper? We built an interface directly atop the OpenTelemetryAPI interface, so you can directly use the tracer from the OTel API to export your work to any collector:

// in Sources/EmbraceOTel/EmbraceOTel.swift
internal var tracer: Tracer {
    OpenTelemetry.instance.tracerProvider.get {
        instrumentationName: instrumentationName,
        instrumentationVersion: instrumentationVersion
    }
} 

//...
public func buildSpan(
    name: String,
    type: SpanType,
    attributes: [String: String]
) {
    let builder = tracer.spanBuilder(spanName: name)
//... function body
    return builder
}

The spanBuilder, when started, returns an object ready for any OTel export. Additionally, the same object type is used by the Embrace SDK to report to Embrace’s backend. So when you start a span, you’re building an object that’ll communicate with all the sources that you need to send data to.

Capturing signals

Included in our SDK’s signals are the Embrace features that we use to report on the most important mobile activities. These are now mapped to OTel signals automatically. To illustrate, let’s cover how this process works with collecting network requests.

In the URLSessionCaptureService, the client-side service that automatically monitors app activity for network requests, the SDK grabs all the information and attributes of the request. This information is then sent on to the DefaultURLSessionTaskHandler, which processes the request and constructs a span with all attributes we think are important to capture for a networking request:

// Sources/EmbraceCore/Capture/Network/URLSessionHandler.swift
final class DefaultURLSessionTaskHandler: URLSessionHandler {
    enum SpanAttribute {
        static let address = "server.address"
        static let url = "url.full"
    // more attributes...
    }

// ...
    func create(task: URLSessionTask) -> Bool {
        let networkSpan = otel
                            .buildSpan(
                                name: name,
                                type: .networkHTTP,
                                attributes: attributes
                            )
    }
}

So, each time an HTTP request is created in the app, the service gathers information about the request AND sends it to the Embrace backend and all connected OTel sources.

Note that capturing network request information is only one of our automatic instruments. We built the `CaptureService` with extensibility in mind, so the community can build and contribute additional ways to automatically instrument frameworks and services within their mobile apps. A requirement of implementing a new `CaptureService`, as defined in the base class, is that the new Service must install OTel This means even the tools we hadn’t yet thought of must provide their signals for export.

Exporting signals

These changes wouldn’t be worth it for an OpenTelemetry diehard or novice if you couldn’t send your OTel signals where you want to. Luckily, right from initial configuration, Embrace’s iOS SDK lets you tell us where the information should go.

In the Embrace.Options object that sets up the SDK, you add an EmbraceOpenTelemetry object with any span or log exporters you’d want.

// Sources/EmbraceCore/Options/Embrace+Options.swift
extension Embrace {
    public final class Options: NSObject {
        public init(
            //...
            export: OpenTelemetryExport
        ) {
            //...
            self.export
        }
    }
}

// Sources/EmbraceCore/Public/OpenTelemetryExport.swift
public class OpenTelemetryExport: NSObject {
    public init(
        spanExporter: SpanExporter?,
        logExporter: LogRecordExporter?
}

These exporters are optional because you might not have an export destination in mind for your data. If you do, though, the exporters sit atop the OpenTelemetry API via the EmbraceOTel wrapper, and will register the export destination for your signals, whether a collector or another vendor. Here is how SpanExporters get added:

// Sources/EmbraceOTel/EmbraceOTel.swift

public static func setup(spanProcessors: [SpanProcessors]) {
    let resource = Resource()
    OpenTelemetry.registerTracerProvider(
        tracerProvider: TracerProviderSDK(
            resource: resource,
            spanProcessors: spanProcessors
        )
    )
}

So, in the end, not only are our signals built on OTel, but our configuration is as well! You can take any telemetry from our toolkit and send it anywhere you’d like. The choice is up to you.

If you’d like to learn more about using the Embrace iOS SDK to export OTel data, check out our tutorial videos or walkthrough blog. You can also submit pull requests on our iOS repo. Feel free to open an issue if you have any questions.

Embrace OpenTelemetry for Mobile

Learn more about leveraging Embrace’s open-source SDKs for mobile observability.

Learn more

Build better mobile apps with Embrace

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