Skip to content

Commit

Permalink
Merge pull request #236 from DataDog/ncreated/RUMM-675-add-start-root…
Browse files Browse the repository at this point in the history
…-span-API

RUMM-675 Add `tracer.startRootSpan()` API
  • Loading branch information
ncreated authored Sep 1, 2020
2 parents 5c7429e + 44d2b2d commit 40b7c77
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 12 deletions.
48 changes: 43 additions & 5 deletions Sources/Datadog/OpenTracing/OTTracer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,35 @@ public protocol OTTracer {
/// Start a new span with the given operation name.
///
/// - parameter operationName: the operation name for the newly-started span
/// - parameter references: an optional list of Reference instances to record causal relationships
/// - parameter tags: a set of tag keys and values per OTSpan#setTag:value:, or nil to start with
/// - parameter references: an optional list of Reference instances to record causal relationships. If no
/// reference is provided, and an active span exists in the current execution context
/// the active span will be used as the parent.
/// - parameter tags: a set of tag keys and values per `OTSpan#setTag:value:`, or `nil` to start with
/// an empty tag map
/// - parameter startTime: an explicitly specified start timestamp for the OTSpan, or nil to use the
/// - parameter startTime: an explicitly specified start timestamp for the `OTSpan`, or `nil` to use the
/// current walltime
/// - returns: a valid Span instance; it is the caller's responsibility to call finish()
/// - returns: a valid Span instance; it is the caller's responsibility to call `finish()`.
func startSpan(
operationName: String,
references: [OTReference]?,
tags: [String: Encodable]?,
startTime: Date?
) -> OTSpan

/// Start a new root span with the given operation name.
/// - Parameters:
/// - operationName: the operation name for the newly-started span
/// - tags: a set of tag keys and values per `OTSpan#setTag:value:`, or `nil` to start with
/// an empty tag map
/// - startTime: an explicitly specified start timestamp for the `OTSpan`, or `nil` to use the
/// current walltime
/// - returns: a valid Span instance; it is the caller's responsibility to call `finish()`.
func startRootSpan(
operationName: String,
tags: [String: Encodable]?,
startTime: Date?
) -> OTSpan

/// Transfer the span information into the carrier of the given format.
///
/// For example:
Expand Down Expand Up @@ -67,7 +83,9 @@ public extension OTTracer {
/// Start a new span with the given operation name.
///
/// - parameter operationName: the operation name for the newly-started span
/// - parameter parent: span context that will be a parent reference
/// - parameter parent: span context that will be a parent reference. If no
/// reference is provided, and an active span exists in the current execution context
/// the active span will be used as the parent.
/// - parameter tags: a set of tag keys and values per OTSpan#setTag:value:, or nil to start with
/// an empty tag map
/// - parameter startTime: an explicitly specified start timestamp for the OTSpan, or nil to use the
Expand All @@ -87,4 +105,24 @@ public extension OTTracer {
startTime: startTime
)
}

/// Start a new root span with the given operation name.
/// - Parameters:
/// - operationName: the operation name for the newly-started span
/// - tags: a set of tag keys and values per `OTSpan#setTag:value:`, or `nil` to start with
/// an empty tag map
/// - startTime: an explicitly specified start timestamp for the `OTSpan`, or `nil` to use the
/// current walltime
/// - returns: a valid Span instance; it is the caller's responsibility to call `finish()`.
func startRootSpan(
operationName: String,
tags: [String: Encodable]? = nil,
startTime: Date? = nil
) -> OTSpan {
return self.startRootSpan(
operationName: operationName,
tags: tags,
startTime: startTime
)
}
}
21 changes: 14 additions & 7 deletions Sources/Datadog/Tracer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,18 @@ public class Tracer: OTTracer {
// MARK: - Open Tracing interface

public func startSpan(operationName: String, references: [OTReference]? = nil, tags: [String: Encodable]? = nil, startTime: Date? = nil) -> OTSpan {
let parentSpanContext = references?.compactMap { $0.context.dd }.last
let spanContext = createSpanContext(parentSpanContext: parentSpanContext)
let parentSpanContext = references?.compactMap { $0.context.dd }.last ?? activeSpan?.context as? DDSpanContext
return startSpan(
spanContext: spanContext,
spanContext: createSpanContext(parentSpanContext: parentSpanContext),
operationName: operationName,
tags: tags,
startTime: startTime
)
}

public func startRootSpan(operationName: String, tags: [String: Encodable]? = nil, startTime: Date? = nil) -> OTSpan {
return startSpan(
spanContext: createSpanContext(parentSpanContext: nil),
operationName: operationName,
tags: tags,
startTime: startTime
Expand All @@ -160,12 +168,11 @@ public class Tracer: OTTracer {
// MARK: - Internal

internal func createSpanContext(parentSpanContext: DDSpanContext? = nil) -> DDSpanContext {
let parentContext = parentSpanContext ?? activeSpan?.context as? DDSpanContext
return DDSpanContext(
traceID: parentContext?.traceID ?? tracingUUIDGenerator.generateUnique(),
traceID: parentSpanContext?.traceID ?? tracingUUIDGenerator.generateUnique(),
spanID: tracingUUIDGenerator.generateUnique(),
parentSpanID: parentContext?.spanID,
baggageItems: BaggageItems(targetQueue: queue, parentSpanItems: parentContext?.baggageItems)
parentSpanID: parentSpanContext?.spanID,
baggageItems: BaggageItems(targetQueue: queue, parentSpanItems: parentSpanContext?.baggageItems)
)
}

Expand Down
31 changes: 31 additions & 0 deletions Tests/DatadogTests/Datadog/TracerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,37 @@ class TracerTests: XCTestCase {
XCTAssertEqual(try spanMatchers[1].parentSpanID(), "0")
}

func testStartingRootActiveSpanInAsynchronousJobs() throws {
TracingFeature.instance = .mockByRecordingSpanMatchers(directory: temporaryDirectory)
defer { TracingFeature.instance = nil }

let tracer = Tracer.initialize(configuration: .init())
let queue = DispatchQueue(label: "\(#function)")

func makeFakeAPIRequest(on queue: DispatchQueue, completion: @escaping () -> Void) {
let requestSpan = tracer.startRootSpan(operationName: "request").setActive()
queue.asyncAfter(deadline: .now() + 1) {
let responseDecodingSpan = tracer.startSpan(operationName: "response decoding")
responseDecodingSpan.finish()
requestSpan.finish()
completion()
}
}
makeFakeAPIRequest(on: queue) {}
makeFakeAPIRequest(on: queue) {}

let spanMatchers = try TracingFeature.waitAndReturnSpanMatchers(count: 4)
let response1Matcher = spanMatchers[0]
let request1Matcher = spanMatchers[1]
let response2Matcher = spanMatchers[2]
let request2Matcher = spanMatchers[3]

XCTAssertEqual(try response1Matcher.parentSpanID(), try request1Matcher.spanID())
XCTAssertEqual(try request1Matcher.parentSpanID(), "0")
XCTAssertEqual(try response2Matcher.parentSpanID(), try request2Matcher.spanID())
XCTAssertEqual(try request2Matcher.parentSpanID(), "0")
}

// MARK: - Sending user info

func testSendingUserInfo() throws {
Expand Down

0 comments on commit 40b7c77

Please sign in to comment.