Skip to main content

Traces

Overview

Embrace’s Traces gives you complete visibility into any customized operation you’d like to track, enabling you to identify, prioritize, and resolve any performance issue. With our tool, you can quickly spot any bottlenecks in your app’s architecture, pinpoint areas you need to troubleshoot with high precision, and ultimately deliver a truly optimized user

Feature Support

The Embrace Traces API allows you to:

  • Create real-time performance timers or record past operations.
    • For real-time tracing, we use a “Stopwatch” concept that enables you to start and stop the timing of a span manually
    • To record a past operation, you can pass in start and end times during span creation.
  • Create child spans that can be attached to a parent.
  • Add attributes and events to each span
    • Attributes have String keys and String values
    • Events also have a set of attributes that have String keys and values.

There is no limit on the duration of spans, but if a crash occurs during a span that is in progress, that span will not be recorded.

Limits

TypeLimit
Max number of spans per session100
Max number of spans per Root Span10
Max number of attributes per span50
Max number of events per span10
Max number of attributes per event10
Length of attribute keys50 characters
Length of attribute values200 characters
Length of Span names50 characters
Length of Event names100 characters
Exceeding Limits

If you exceed the listed limits, the operation with the limit-exceeding call will fail and return a value indicating that there is a failure. See the API documentation for details.

Naming Conventions

  • Span Names are case-sensitive and are a max of 50 characters.
  • Key Names are case-sensitive, have a max of 50 characters, and are alpha-numeric
Internal Prefixes

The emb- and emb. prefixes are reserved for internal Embrace span names and attribute keys. You should never create a name with emb- and emb. prefixes

Integration Steps

To use this feature:

  1. Ensure you’re using a version of the Embrace SDK that supports Traces.
  2. Instrument your app using the reference guide in this sections to start adding spans to your operations.
  3. See the spans in the Traces section of the Embrace dashboard.

Create SpanBuilder

To trace an in-progress operation, use the Embrace.client instance to create a Span. This span is atop the OpenTelemetry API and builds an OTel-exportable span.

Note: Until the span is started, the .buildSpan method below and any decorators return a SpanBuilder object.

let spanBuilder = Embrace
.client?
.buildSpan(
name: "process-image",
type: .performance, //default argument
attributes: [String:String]() //default argument
)

The type argument indicates the purpose of the span and sets an emb.type attribute on the span object, which is used to aggregate alike spans in the Embrace dashboard. The attributes argument adds custom attributes to the span object.

Start Span

Spans must be started and ended to ultimately be recorded. Use .startSpan to begin recording the span.

let spanBuilder = Embrace
.client?
.buildSpan(name: "process-image")

let span = spanBuilder.startSpan()

// is the same as
let span = Embrace
.client?
.buildSpan(name: "process-image")
.startSpan()

Using .startSpan sets the startTime of the span as the present time (Date.now). If your use case necessitates starting the span at a time other than .now, you can set that before beginning the span:

let span = Embrace
.client?
.buildSpan(name: "process-image")
.setStartTime(time: Date().advanced(by: -6.0))
.startSpan()

Parent-Child Span Relationship

A span can be indicated as the child of another span by setting its parent. This must be set on the SpanBuilder object, so you should set the parent before starting your span.

// Create a root span with a custom name
let parentSpan = Embrace
.client?
.buildSpan(name: "process-batch")
.startSpan()

// Create a child span by setting the parent span prior to start
let childSpan = Embrace
.client?
.buildSpan(name: "process-item")
.setParent(parentSpan)
.startSpan()

Adding Events and Attributes

You can add Events and Attributes to your spans. Events and Attributes might seem similar, but note that Events are added with timestamps and can themselves contain Attributes.

// Add span events to mark points in time
span.addEvent(
name: "image-render-complete",
attributes: [ "size" : .int(3) ],
timestamp: Date.now
)

// Add attributes to spans to provide context
span.setAttribute(key: "product.id", value: "ABC123")

End Spans

Spans must be ended to be recorded when the session is captured. Ending a span will also export the signal to any OTel exporters that have been configured in the app.

// Stop span at current time, considered successful
span.end()

// Stop span at a particular time, considered successful
span2.end(time: time.advanced(by: 3.0))

// Stop span at current time with explicit error code
span3.end(errorCode: .userAbandon)

Recording a Completed Span

You can also create a completed span after the fact. This function returns Void

let startTime = Date()
let endTime = startTime.addingTimeInterval(4.0)

// manually record operation timing after it occurs
Embrace
.client?.
.recordCompletedSpan(
name: "deserialize-data-blob",
type: .performance,
parent: nil,
startTime: startTime,
endTime: endTime,
attributes: [:],
events: [],
errorCode: nil
)

Spans as object properties

To, for example, store a Span in object scope, you will need to import Span from the OpenTelemetry API:

/* ******************************* */
// Imports for new object
import Foundation
import EmbraceIO
import OpenTelemetryApi

// New object definition
class MyClass {

// Create a Span property that will be available across the object
var activitySpan: Span? = nil // Span here comes from `OpenTelemetryApi`, not `EmbraceIO`

func activityStart() {
// Something starts
// ...
// And we want to trace it
activitySpan = Embrace.client?.buildSpan(name: "activity")
.startSpan()
}

func activityChanged() {
// Something changed
// ...
// And we want to note it
activitySpan?.addEvent(name: "activity-changed")
}

func activitySuccessfully() {
// Something ended
// ...
activitySpan?.end()
}

func activityEnded(with failure: EmbraceIO.ErrorCode) {
// Something ended unsuccessfully
// ...
activitySpan?.end(errorCode: failure)
}
}

Span auto termination

In accordance with the OTel specification, spans in the Embrace SDK do not end by default when the session span (technically their parent) ends. You can flag a span to be auto terminated if it's still open when the Embrace session ends. When building a span, you'll have to pass the SpanErrorCode to be used when terminating the span.

let span = Embrace
.client?
.buildSpan(name: "process-image", autoTerminationCode: .failure)
.startSpan()
info

Child spans of a span flagged for auto termination will be terminated along with their parent.