Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUMM-3374 fix: Manual trace injection APIs are not available in DatadogTrace #1415

Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Unreleased

- [BUGFIX] Manual trace injection APIs are not available in DatadogTrace. See [#1415][].
- [BUGFIX] Allow instantiating custom instance of the SDK after default one. See [#1413][].
- [BUGFIX] Do not propagate attributes from Errors and LongTasks to Views.
- [IMPROVEMENT] Upgrade to PLCrashReporter 1.11.1.
Expand Down Expand Up @@ -496,6 +497,7 @@ Release `2.0` introduces breaking changes. Follow the [Migration Guide](MIGRATIO
[#1355]: https://github.com/DataDog/dd-sdk-ios/pull/1355
[#1410]: https://github.com/DataDog/dd-sdk-ios/pull/1410
[#1413]: https://github.com/DataDog/dd-sdk-ios/pull/1413
[#1415]: https://github.com/DataDog/dd-sdk-ios/pull/1415
[#1419]: https://github.com/DataDog/dd-sdk-ios/pull/1419
[@00fa9a]: https://github.com/00FA9A
[@britton-earnin]: https://github.com/Britton-Earnin
Expand Down
100 changes: 52 additions & 48 deletions Datadog/Datadog.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion Datadog/E2ETests/Tracing/TracerE2ETests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

import DatadogCore
import DatadogInternal
import DatadogTrace

class TracerE2ETests: E2ETests {
Expand Down
54 changes: 51 additions & 3 deletions Datadog/Example/Base.lproj/Main iOS.storyboard
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="gra-d4-cht">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="gra-d4-cht">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
Expand Down Expand Up @@ -65,8 +65,28 @@
<segue destination="FaI-gu-eql" kind="show" id="ePB-Ph-XzE"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="M3j-VO-N1P" style="IBUITableViewCellStyleDefault" id="F5A-gJ-7Vm">
<rect key="frame" x="0.0" y="137" width="414" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="F5A-gJ-7Vm" id="Y3A-pt-TCA">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Trace Injection (manual)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="M3j-VO-N1P">
<rect key="frame" x="20" y="0.0" width="374" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="1Dj-vX-hFb" kind="show" id="IrQ-UG-cMw"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="yCu-pq-IYL" style="IBUITableViewCellStyleDefault" id="3G8-Wa-fSQ">
<rect key="frame" x="0.0" y="131.5" width="414" height="43.5"/>
<rect key="frame" x="0.0" y="180.5" width="414" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="3G8-Wa-fSQ" id="7IJ-XI-RAR">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
Expand Down Expand Up @@ -1662,6 +1682,34 @@
</objects>
<point key="canvasLocation" x="1419" y="1175"/>
</scene>
<!--Debug Manual Trace Injection View Controller-->
<scene sceneID="d34-e7-Qn8">
<objects>
<viewController id="1Dj-vX-hFb" customClass="DebugManualTraceInjectionViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="h6o-Ng-hRs">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="This screen requires iO14+" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pe0-Ro-rxm">
<rect key="frame" x="105" y="437.5" width="204" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="LmF-Gg-KKf"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="pe0-Ro-rxm" firstAttribute="centerX" secondItem="h6o-Ng-hRs" secondAttribute="centerX" id="WU4-aG-e4N"/>
<constraint firstItem="pe0-Ro-rxm" firstAttribute="centerY" secondItem="h6o-Ng-hRs" secondAttribute="centerY" id="cB7-WP-Qma"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="yjy-W3-IxO"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="R6e-tl-J7Q" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2201" y="1175"/>
</scene>
</scenes>
<resources>
<systemColor name="secondaryLabelColor">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* 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 SwiftUI
import DatadogTrace

@available(iOS 14, *)
internal class DebugManualTraceInjectionViewController: UIHostingController<DebugManualTraceInjectionView> {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder, rootView: DebugManualTraceInjectionView())
}
}

private var currentSession: URLSession? = nil

@available(iOS 14.0, *)
internal struct DebugManualTraceInjectionView: View {
enum TraceHeaderType: String, CaseIterable {
case datadog = "Datadog"
case w3c = "W3C"
case b3Single = "B3-Single"
case b3Multiple = "B3-Multiple"
}

@State private var spanName = "network request"
@State private var requestURL = "http://127.0.0.1:8000"
@State private var selectedTraceHeaderType: TraceHeaderType = .datadog
@State private var sampleRate: Float = 100.0
@State private var isRequestPending = false

private let session: URLSession = URLSession(
configuration: .ephemeral,
delegate: DDURLSessionDelegate(),
delegateQueue: nil
)

var body: some View {
let isButtonDisabled = isRequestPending || spanName.isEmpty || requestURL.isEmpty

VStack() {
VStack(spacing: 8) {
Text("Trace injection")
.font(.caption.weight(.bold))
.frame(maxWidth: .infinity, alignment: .leading)

Text("After tapping \"SEND REQUEST\", a POST request will be sent to the given URL. The request will be traced using the chosen tracing header type and sample rate. A span with specified name will be sent to Datadog.")
.font(.caption.weight(.light))
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding()

Form {
Section(header: Text("Traced URL:")) {
TextField("", text: $requestURL)
}
Section(header: Text("Span name:")) {
TextField("", text: $spanName)
}
Picker("Trace header type:", selection: $selectedTraceHeaderType) {
ForEach(TraceHeaderType.allCases, id: \.self) { headerType in
Text(headerType.rawValue)
}
}
.pickerStyle(.inline)
Section(header: Text("Trace sample Rate")) {
Slider(
value: $sampleRate,
in: 0...100, step: 1,
minimumValueLabel: Text("0"),
maximumValueLabel: Text("100")
) {
Text("Sample Rate")
}
}
}

Spacer()

Button(action: { prepareAndSendRequest() }) {
Text("SEND REQUEST")
.fontWeight(.bold)
.foregroundColor(.white)
}
.frame(maxWidth: .infinity)
.padding()
.background(isButtonDisabled ? Color.gray : Color.datadogPurple)
.cornerRadius(10)
.disabled(isButtonDisabled)
.padding(.horizontal, 8)
.padding(.bottom, 30)
}
}

private func prepareAndSendRequest() {
guard let url = URL(string: requestURL) else {
print("πŸ”₯ POST Request not sent - invalid url: \(requestURL)")
return
}

var request = URLRequest(url: url)
request.httpMethod = "POST"

let span = Tracer.shared().startRootSpan(operationName: spanName)

switch selectedTraceHeaderType {
case .datadog:
let writer = HTTPHeadersWriter(sampleRate: sampleRate)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .w3c:
let writer = W3CHTTPHeadersWriter(sampleRate: sampleRate)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .b3Single:
let writer = B3HTTPHeadersWriter(sampleRate: sampleRate, injectEncoding: .single)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .b3Multiple:
let writer = B3HTTPHeadersWriter(sampleRate: sampleRate, injectEncoding: .multiple)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
}

send(request: request) {
span.finish()
print("βœ… Request sent to \(requestURL)")
}
}

private func send(request: URLRequest, completion: @escaping () -> Void) {
isRequestPending = true
let task = session.dataTask(with: request) { _, _, _ in
completion()
DispatchQueue.main.async { self.isRequestPending = false }
}
task.resume()
}
}

// MARK - Preview

@available(iOS 14.0, *)

struct DebugTraceInjectionView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
DebugManualTraceInjectionView()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import UIKit
import WebKit
import DatadogInternal
import DatadogRUM
import DatadogWebViewTracking

Expand Down
1 change: 0 additions & 1 deletion Datadog/Example/Utils/ConsoleOutputInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

#if DEBUG

import DatadogInternal
import UIKit

class ConsoleOutputInterceptor {
Expand Down
28 changes: 14 additions & 14 deletions DatadogCore/Tests/Datadog/TracerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -744,14 +744,14 @@ class TracerTests: XCTestCase {
XCTAssertEqual(httpHeadersWriter.traceHeaderFields, expectedHTTPHeaders2)
}

func testItInjectsSpanContextWithOTelHTTPHeadersWriter_usingMultipleHeaders() {
func testItInjectsSpanContextWithB3HTTPHeadersWriter_usingMultipleHeaders() {
Trace.enable(with: config, in: core)
let tracer = Tracer.shared(in: core)
let spanContext1 = DDSpanContext(traceID: 1, spanID: 2, parentSpanID: 3, baggageItems: .mockAny())
let spanContext2 = DDSpanContext(traceID: 4, spanID: 5, parentSpanID: 6, baggageItems: .mockAny())
let spanContext3 = DDSpanContext(traceID: 77, spanID: 88, parentSpanID: nil, baggageItems: .mockAny())

let httpHeadersWriter = OTelHTTPHeadersWriter(sampler: .mockKeepAll(), injectEncoding: .multiple)
let httpHeadersWriter = B3HTTPHeadersWriter(sampler: .mockKeepAll(), injectEncoding: .multiple)
XCTAssertEqual(httpHeadersWriter.traceHeaderFields, [:])

// When
Expand Down Expand Up @@ -790,14 +790,14 @@ class TracerTests: XCTestCase {
XCTAssertEqual(httpHeadersWriter.traceHeaderFields, expectedHTTPHeaders3)
}

func testItInjectsSpanContextWithOTelHTTPHeadersWriter_usingSingleHeader() {
func testItInjectsSpanContextWithB3HTTPHeadersWriter_usingSingleHeader() {
Trace.enable(with: config, in: core)
let tracer = Tracer.shared(in: core)
let spanContext1 = DDSpanContext(traceID: 1, spanID: 2, parentSpanID: 3, baggageItems: .mockAny())
let spanContext2 = DDSpanContext(traceID: 4, spanID: 5, parentSpanID: 6, baggageItems: .mockAny())
let spanContext3 = DDSpanContext(traceID: 77, spanID: 88, parentSpanID: nil, baggageItems: .mockAny())

let httpHeadersWriter = OTelHTTPHeadersWriter(sampler: .mockKeepAll(), injectEncoding: .single)
let httpHeadersWriter = B3HTTPHeadersWriter(sampler: .mockKeepAll(), injectEncoding: .single)
XCTAssertEqual(httpHeadersWriter.traceHeaderFields, [:])

// When
Expand Down Expand Up @@ -828,12 +828,12 @@ class TracerTests: XCTestCase {
XCTAssertEqual(httpHeadersWriter.traceHeaderFields, expectedHTTPHeaders3)
}

func testItInjectsRejectedSpanContextWithOTelHTTPHeadersWriter_usingSingleHeader() {
func testItInjectsRejectedSpanContextWithB3HTTPHeadersWriter_usingSingleHeader() {
Trace.enable(with: config, in: core)
let tracer = Tracer.shared(in: core)
let spanContext = DDSpanContext(traceID: 1, spanID: 2, parentSpanID: .mockAny(), baggageItems: .mockAny())

let httpHeadersWriter = OTelHTTPHeadersWriter(sampler: .mockRejectAll())
let httpHeadersWriter = B3HTTPHeadersWriter(sampler: .mockRejectAll())
XCTAssertEqual(httpHeadersWriter.traceHeaderFields, [:])

// When
Expand All @@ -846,12 +846,12 @@ class TracerTests: XCTestCase {
XCTAssertEqual(httpHeadersWriter.traceHeaderFields, expectedHTTPHeaders)
}

func testItInjectsRejectedSpanContextWithOTelHTTPHeadersWriter_usingMultipleHeader() {
func testItInjectsRejectedSpanContextWithB3HTTPHeadersWriter_usingMultipleHeader() {
Trace.enable(with: config, in: core)
let tracer = Tracer.shared(in: core)
let spanContext = DDSpanContext(traceID: 1, spanID: 2, parentSpanID: .mockAny(), baggageItems: .mockAny())

let httpHeadersWriter = OTelHTTPHeadersWriter(sampler: .mockRejectAll(), injectEncoding: .multiple)
let httpHeadersWriter = B3HTTPHeadersWriter(sampler: .mockRejectAll(), injectEncoding: .multiple)
XCTAssertEqual(httpHeadersWriter.traceHeaderFields, [:])

// When
Expand Down Expand Up @@ -956,15 +956,15 @@ class TracerTests: XCTestCase {
XCTAssertNil(extractedSpanContext?.dd.parentSpanID)
}

func testItExtractsSpanContextWithOTelHTTPHeadersReader_forMultipleHeaders() {
func testItExtractsSpanContextWithB3HTTPHeadersReader_forMultipleHeaders() {
Trace.enable(with: config, in: core)
let tracer = Tracer.shared(in: core)
let injectedSpanContext = DDSpanContext(traceID: 1, spanID: 2, parentSpanID: 3, baggageItems: .mockAny())

let httpHeadersWriter = OTelHTTPHeadersWriter(sampler: .mockKeepAll(), injectEncoding: .multiple)
let httpHeadersWriter = B3HTTPHeadersWriter(sampler: .mockKeepAll(), injectEncoding: .multiple)
tracer.inject(spanContext: injectedSpanContext, writer: httpHeadersWriter)

let httpHeadersReader = OTelHTTPHeadersReader(
let httpHeadersReader = B3HTTPHeadersReader(
httpHeaderFields: httpHeadersWriter.traceHeaderFields
)
let extractedSpanContext = tracer.extract(reader: httpHeadersReader)
Expand All @@ -974,15 +974,15 @@ class TracerTests: XCTestCase {
XCTAssertEqual(extractedSpanContext?.dd.parentSpanID, injectedSpanContext.dd.parentSpanID)
}

func testItExtractsSpanContextWithOTelHTTPHeadersReader_forSingleHeader() {
func testItExtractsSpanContextWithB3HTTPHeadersReader_forSingleHeader() {
Trace.enable(with: config, in: core)
let tracer = Tracer.shared(in: core)
let injectedSpanContext = DDSpanContext(traceID: 1, spanID: 2, parentSpanID: 3, baggageItems: .mockAny())

let httpHeadersWriter = OTelHTTPHeadersWriter(sampler: .mockKeepAll(), injectEncoding: .single)
let httpHeadersWriter = B3HTTPHeadersWriter(sampler: .mockKeepAll(), injectEncoding: .single)
tracer.inject(spanContext: injectedSpanContext, writer: httpHeadersWriter)

let httpHeadersReader = OTelHTTPHeadersReader(
let httpHeadersReader = B3HTTPHeadersReader(
httpHeaderFields: httpHeadersWriter.traceHeaderFields
)
let extractedSpanContext = tracer.extract(reader: httpHeadersReader)
Expand Down
Loading