Skip to content

Commit

Permalink
Merge pull request #1415 from DataDog/ncreated/RUMM-3374/fix-manual-t…
Browse files Browse the repository at this point in the history
…race-injection-impossible

RUMM-3374 fix: Manual trace injection APIs are not available in `DatadogTrace`
  • Loading branch information
ncreated authored Aug 18, 2023
2 parents e21b0f5 + 99dbb48 commit 12a92d3
Show file tree
Hide file tree
Showing 36 changed files with 731 additions and 451 deletions.
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] Fix session replay uploads to AP1 site. See [#1418][].
- [BUGFIX] Allow instantiating custom instance of the SDK after default one. See [#1413][].
- [BUGFIX] Do not propagate attributes from Errors and LongTasks to Views.
Expand Down Expand Up @@ -497,6 +498,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
[#1418]: https://github.com/DataDog/dd-sdk-ios/pull/1418
[#1419]: https://github.com/DataDog/dd-sdk-ios/pull/1419
[@00fa9a]: https://github.com/00FA9A
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()
}
}
}
1 change: 0 additions & 1 deletion Datadog/Example/Debugging/DebugWebviewViewController.swift
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

0 comments on commit 12a92d3

Please sign in to comment.