Skip to content

Commit

Permalink
RUM-1836 feat(otel-tracer): implement core functionality of the otel …
Browse files Browse the repository at this point in the history
…tracer
  • Loading branch information
ganeshnj committed Jan 3, 2024
1 parent 87ea047 commit 6e552e1
Show file tree
Hide file tree
Showing 11 changed files with 413 additions and 61 deletions.
3 changes: 2 additions & 1 deletion DatadogTrace/Sources/DDNoOps.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ internal class DDNoopTracer: OTTracer, OpenTelemetryApi.Tracer {
// MARK: - Open Telemetry

func spanBuilder(spanName: String) -> OpenTelemetryApi.SpanBuilder {
fatalError("Not implemented")
warn()
return OTelNoOpSpanBuilder()
}
}

Expand Down
10 changes: 9 additions & 1 deletion DatadogTrace/Sources/DatadogTracer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ internal class DatadogTracer: OTTracer, OpenTelemetryApi.Tracer {
// MARK: - OpenTelemetry

func spanBuilder(spanName: String) -> OpenTelemetryApi.SpanBuilder {
OTelSpanBuilder()
OTelSpanBuilder(
active: false,
attributes: [:],
parent: .currentSpan,
spanKind: .client,
spanName: spanName,
startTime: nil,
tracer: self
)
}
}
8 changes: 4 additions & 4 deletions DatadogTrace/Sources/OpenTelemetry/OTelNoOpSpan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@
import Foundation
import OpenTelemetryApi

class OTelNoOpSpan: Span {
internal class OTelNoOpSpan: Span {
var kind: OpenTelemetryApi.SpanKind = .internal

var name: String = ""

var context: SpanContext = SpanContext.create(
var context = SpanContext.create(
traceId: TraceId.invalid,
spanId: SpanId.invalid,
traceFlags: TraceFlags(),
traceState: TraceState()
)

var isRecording: Bool = false
var isRecording = false

var status: Status = Status.unset
var status = Status.unset

var description: String = "NoOpSpan"

Expand Down
28 changes: 18 additions & 10 deletions DatadogTrace/Sources/OpenTelemetry/OTelNoOpSpanBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,48 @@
import Foundation
import OpenTelemetryApi

class NoOpSpanBuilder: SpanBuilder {
@discardableResult public func startSpan() -> Span {
internal class OTelNoOpSpanBuilder: SpanBuilder {
@discardableResult
func startSpan() -> Span {
return OTelNoOpSpan()
}

@discardableResult public func setParent(_ parent: Span) -> Self {
@discardableResult
func setParent(_ parent: Span) -> Self {
return self
}

@discardableResult public func setParent(_ parent: SpanContext) -> Self {
@discardableResult
func setParent(_ parent: SpanContext) -> Self {
return self
}

@discardableResult public func setNoParent() -> Self {
@discardableResult
func setNoParent() -> Self {
return self
}

@discardableResult public func addLink(spanContext: SpanContext) -> Self {
@discardableResult
func addLink(spanContext: SpanContext) -> Self {
return self
}

@discardableResult public func addLink(spanContext: SpanContext, attributes: [String: OpenTelemetryApi.AttributeValue]) -> Self {
@discardableResult
func addLink(spanContext: SpanContext, attributes: [String: OpenTelemetryApi.AttributeValue]) -> Self {
return self
}

@discardableResult public func setSpanKind(spanKind: SpanKind) -> Self {
@discardableResult
func setSpanKind(spanKind: SpanKind) -> Self {
return self
}

@discardableResult public func setStartTime(time: Date) -> Self {
@discardableResult
func setStartTime(time: Date) -> Self {
return self
}

public func setAttribute(key: String, value: OpenTelemetryApi.AttributeValue) -> Self {
func setAttribute(key: String, value: OpenTelemetryApi.AttributeValue) -> Self {
return self
}

Expand Down
123 changes: 94 additions & 29 deletions DatadogTrace/Sources/OpenTelemetry/OTelSpan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,29 @@
import Foundation
import OpenTelemetryApi

class OTelSpan: OpenTelemetryApi.Span {
private let tracer: DatadogTracer
private let queue: DispatchQueue
internal enum DatadogTagKeys: String {
case spanKind = "span.kind"
case errorMessage = "error.Message"
}

internal class OTelSpan: OpenTelemetryApi.Span {
private var _status: OpenTelemetryApi.Status
private var _name: String

init(
context: OpenTelemetryApi.SpanContext,
kind: OpenTelemetryApi.SpanKind,
name: String,
tracer: DatadogTracer
) {
self._name = name
self._status = .unset
self.context = context
self.isRecording = true
self.kind = kind
self.queue = tracer.queue
self.tracer = tracer
}

var attributes: [String: OpenTelemetryApi.AttributeValue]
let context: OpenTelemetryApi.SpanContext
var kind: OpenTelemetryApi.SpanKind
let nestedSpan: DDSpan
let tracer: DatadogTracer
let queue: DispatchQueue

var context: OpenTelemetryApi.SpanContext

/// `isRecording` indicates whether the span is recording or not
/// and events can be added to it.
var isRecording: Bool

/// `status` saves state of the code and description indicating
/// whether the span has recorded errors. This will be done by setting `error.message`
/// tag on the span.
var status: OpenTelemetryApi.Status {
get {
queue.sync {
Expand All @@ -42,11 +38,16 @@ class OTelSpan: OpenTelemetryApi.Span {
}
set {
queue.sync {
guard isRecording else {
return
}

_status = newValue
}
}
}

/// `name` of the span is akin to operation name in Datadog
var name: String {
get {
queue.sync {
Expand All @@ -55,40 +56,104 @@ class OTelSpan: OpenTelemetryApi.Span {
}
set {
queue.sync {
guard isRecording else {
return
}
_name = newValue
}
nestedSpan.setOperationName(name)
}
}

init(
attributes: [String: OpenTelemetryApi.AttributeValue],
kind: OpenTelemetryApi.SpanKind,
name: String,
parentSpanID: OpenTelemetryApi.SpanId?,
spanContext: OpenTelemetryApi.SpanContext,
spanKind: OpenTelemetryApi.SpanKind,
startTime: Date,
tracer: DatadogTracer
) {
self._name = name
self._status = .unset
self.attributes = attributes
self.context = spanContext
self.kind = kind
self.isRecording = true
self.queue = tracer.queue
self.tracer = tracer
self.nestedSpan = .init(
tracer: tracer,
context: .init(
traceID: context.traceId.toDatadog(),
spanID: context.spanId.toDatadog(),
parentSpanID: parentSpanID?.toDatadog(),
baggageItems: .init()
),
operationName: name,
startTime: startTime,
tags: [:]
)
}

// swiftlint:disable unavailable_function
func addEvent(name: String) {
fatalError("Not implemented")
fatalError("Not implemented yet")
}

func addEvent(name: String, timestamp: Date) {
fatalError("Not implemented")
fatalError("Not implemented yet")
}

func addEvent(name: String, attributes: [String : OpenTelemetryApi.AttributeValue]) {
fatalError("Not implemented")
func addEvent(name: String, attributes: [String: OpenTelemetryApi.AttributeValue]) {
fatalError("Not implemented yet")
}

func addEvent(name: String, attributes: [String : OpenTelemetryApi.AttributeValue], timestamp: Date) {
fatalError("Not implemented")
func addEvent(name: String, attributes: [String: OpenTelemetryApi.AttributeValue], timestamp: Date) {
fatalError("Not implemented yet")
}
// swiftlint:enable unavailable_function

func end() {
fatalError("Not implemented")
end(time: Date())
}

func end(time: Date) {
fatalError("Not implemented")
queue.sync {
guard isRecording else {
return
}
isRecording = false

// Attributes maps to tags in Datadog
for (key, value) in attributes {
nestedSpan.setTag(key: key, value: value.description)
}

// If status is error, error.message tag is added
switch self._status {
case .error(description: let description):
nestedSpan.setTag(key: DatadogTagKeys.errorMessage.rawValue, value: description)
case .ok, .unset:
break
}

// SpanKind maps to the `span.kind` tag in Datadog
nestedSpan.setTag(key: DatadogTagKeys.spanKind.rawValue, value: kind.rawValue)
}
nestedSpan.finish(at: time)
}

var description: String {
return "WrapperSpan"
}

func setAttribute(key: String, value: OpenTelemetryApi.AttributeValue?) {
fatalError("Not implemented")
guard isRecording else {
return
}

attributes[key] = value
}
}
Loading

0 comments on commit 6e552e1

Please sign in to comment.