-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1630 from DataDog/ganeshnj/feat/otel-tracer-span-…
…links RUM-1836 feat(otel-tracer): add support for span links
- Loading branch information
Showing
8 changed files
with
290 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2019-Present Datadog, Inc. | ||
*/ | ||
|
||
import Foundation | ||
import OpenTelemetryApi | ||
|
||
/// Represents a span link containing a `SpanContext` and additional attributes. | ||
internal struct OTelSpanLink: Equatable { | ||
/// Context of the linked span. | ||
let context: OpenTelemetryApi.SpanContext | ||
|
||
/// Additional attributes of the linked span. | ||
let attributes: [String: OpenTelemetryApi.AttributeValue] | ||
} | ||
|
||
extension OTelSpanLink: Encodable { | ||
enum CodingKeys: String, CodingKey { | ||
case traceId = "trace_id" | ||
case spanId = "span_id" | ||
case attributes = "attributes" | ||
case traceState = "tracestate" | ||
case traceFlags = "flags" | ||
} | ||
|
||
/// Encodes the span link to the following JSON format: | ||
/// ```json | ||
/// { | ||
/// "trace_id": "<exactly 32 character, zero-padded lower-case hexadecimal encoded trace id>", | ||
/// "span_id": "<exactly 16 character, zero-padded lower-case hexadecimal encoded span id>", | ||
/// "attributes": {"key":"value", "pairs":"of", "arbitrary":"values"}, | ||
/// "dropped_attributes_count": <decimal 64 bit integer>, | ||
/// "tracestate": "a tracestate as defined in the W3C standard", | ||
/// "flags": <an integer representing the flags as defined in the W3C standard> | ||
/// }, | ||
/// ``` | ||
/// - Parameter encoder: Encoder | ||
func encode(to encoder: Encoder) throws { | ||
var container = encoder.container(keyedBy: CodingKeys.self) | ||
let traceId = String(context.traceId.toDatadog(), representation: .hexadecimal32Chars) | ||
|
||
try container.encode(traceId, forKey: .traceId) | ||
try container.encode(context.spanId.hexString, forKey: .spanId) | ||
if !attributes.isEmpty { | ||
try container.encode(attributes.tags, forKey: .attributes) | ||
} | ||
|
||
if !context.traceState.entries.isEmpty { | ||
try container.encode(context.traceState.w3c(), forKey: .traceState) | ||
} | ||
try container.encode(context.traceFlags.byte, forKey: .traceFlags) | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
DatadogTrace/Sources/OpenTelemetry/OTelTraceState+Datadog.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2019-Present Datadog, Inc. | ||
*/ | ||
|
||
import Foundation | ||
import OpenTelemetryApi | ||
|
||
extension OpenTelemetryApi.TraceState { | ||
/// Returns the tracestate as a string as defined in the W3C standard. | ||
/// https://www.w3.org/TR/trace-context/#tracestate-header-field-values | ||
/// Example: rojo=00f067aa0ba902b7,congo=t61rcWkgMzE | ||
/// - Returns: tracestate as a string | ||
public func w3c() -> String { | ||
return self.entries.map { "\($0.key)=\($0.value)" }.joined(separator: ",") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2019-Present Datadog, Inc. | ||
*/ | ||
|
||
import XCTest | ||
import TestUtilities | ||
import DatadogInternal | ||
import OpenTelemetryApi | ||
|
||
@testable import DatadogTrace | ||
|
||
final class OTelSpanLinkTests: XCTestCase { | ||
func testEncoder_givenAllPropertiesArePresent() throws { | ||
let encoder = JSONEncoder() | ||
let traceId = TraceId(idHi: 101, idLo: 102) | ||
let spanId = SpanId(id: 103) | ||
var traceFlags = TraceFlags() | ||
traceFlags.setIsSampled(true) | ||
let traceState = TraceState( | ||
entries: [ | ||
.init(key: "foo", value: "bar")!, | ||
.init(key: "bar", value: "baz")! | ||
] | ||
)! | ||
|
||
let spanContext = OpenTelemetryApi.SpanContext.create( | ||
traceId: traceId, | ||
spanId: spanId, | ||
traceFlags: traceFlags, | ||
traceState: traceState | ||
) | ||
let attributes: [String: OpenTelemetryApi.AttributeValue] = [ | ||
"foo": .string("bar") | ||
] | ||
|
||
let spanLink = OTelSpanLink( | ||
context: spanContext, | ||
attributes: attributes | ||
) | ||
|
||
let encoded = try encoder.encode(spanLink) | ||
let decoded = try JSONDecoder().decode([String: AnyDecodable].self, from: encoded) | ||
|
||
XCTAssertEqual(decoded["trace_id"]?.value as? String, "00000000000000000000000000000065") | ||
XCTAssertEqual(decoded["span_id"]?.value as? String, "0000000000000067") | ||
XCTAssertEqual(decoded["attributes"]?.value as? [String: String], ["foo": "bar"]) | ||
XCTAssertEqual(decoded["tracestate"]?.value as? String, "foo=bar,bar=baz") | ||
XCTAssertEqual(decoded["flags"]?.value as? Int, 1) | ||
} | ||
|
||
func testEncoder_givenOnlyRequiredPropertiesArePresent() throws { | ||
let encoder = JSONEncoder() | ||
let traceId = TraceId(idHi: 101, idLo: 102) | ||
let spanId = SpanId(id: 103) | ||
let traceFlags = TraceFlags() | ||
let traceState = TraceState() | ||
|
||
let spanContext = OpenTelemetryApi.SpanContext.create( | ||
traceId: traceId, | ||
spanId: spanId, | ||
traceFlags: traceFlags, | ||
traceState: traceState | ||
) | ||
|
||
let spanLink = OTelSpanLink( | ||
context: spanContext, | ||
attributes: [:] | ||
) | ||
|
||
let encoded = try encoder.encode(spanLink) | ||
let decoded = try JSONDecoder().decode([String: AnyDecodable].self, from: encoded) | ||
|
||
XCTAssertEqual(decoded["trace_id"]?.value as? String, "00000000000000000000000000000065") | ||
XCTAssertEqual(decoded["span_id"]?.value as? String, "0000000000000067") | ||
XCTAssertNil(decoded["attributes"]?.value) | ||
XCTAssertNil(decoded["tracestate"]?.value) | ||
XCTAssertEqual(decoded["flags"]?.value as? Int, 0) | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
DatadogTrace/Tests/OpenTelemetry/OTelTraceState+DatadogTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2019-Present Datadog, Inc. | ||
*/ | ||
|
||
import XCTest | ||
import TestUtilities | ||
import DatadogInternal | ||
import OpenTelemetryApi | ||
|
||
@testable import DatadogTrace | ||
|
||
final class OTelTraceStateDatadogTests: XCTestCase { | ||
func testW3C_givenEmptyEntries() throws { | ||
let traceState = TraceState(entries: [])! | ||
XCTAssertEqual("", traceState.w3c()) | ||
} | ||
|
||
func testW3C_givenSomeEntries() throws { | ||
let traceState = TraceState( | ||
entries: [ | ||
.init(key: "foo", value: "bar")!, | ||
.init(key: "bar", value: "baz")! | ||
] | ||
)! | ||
|
||
XCTAssertEqual("foo=bar,bar=baz", traceState.w3c()) | ||
} | ||
} |
Oops, something went wrong.