Skip to content

Commit

Permalink
Merge pull request #1954 from DataDog/ganeshnj/chore/dist-trace-manua…
Browse files Browse the repository at this point in the history
…l-testing
  • Loading branch information
ganeshnj authored Jul 17, 2024
2 parents 56d50a1 + e0bcff3 commit d80d1cf
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 41 deletions.
4 changes: 4 additions & 0 deletions Datadog/Datadog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
3C5D636D2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5D636B2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift */; };
3C5D691F2B76825500C4E07E /* OpenTelemetryApi.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C1F88222B767CE200821579 /* OpenTelemetryApi.xcframework */; };
3C5D69222B76826000C4E07E /* OpenTelemetryApi.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C1F88222B767CE200821579 /* OpenTelemetryApi.xcframework */; };
3C62C3612C3E852F00C7E336 /* MultiSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C62C3602C3E852F00C7E336 /* MultiSelector.swift */; };
3C6C7FE72B459AAA006F5CBC /* OTelSpan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C6C7FE02B459AAA006F5CBC /* OTelSpan.swift */; };
3C6C7FE82B459AAA006F5CBC /* OTelSpan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C6C7FE02B459AAA006F5CBC /* OTelSpan.swift */; };
3C6C7FE92B459AAA006F5CBC /* OTelSpanBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C6C7FE12B459AAA006F5CBC /* OTelSpanBuilder.swift */; };
Expand Down Expand Up @@ -2109,6 +2110,7 @@
3C43A3862C188970000BFB21 /* WatchdogTerminationMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchdogTerminationMonitorTests.swift; sourceTree = "<group>"; };
3C5D63682B55512B00FEB4BA /* OTelTraceState+Datadog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OTelTraceState+Datadog.swift"; sourceTree = "<group>"; };
3C5D636B2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OTelTraceState+DatadogTests.swift"; sourceTree = "<group>"; };
3C62C3602C3E852F00C7E336 /* MultiSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiSelector.swift; sourceTree = "<group>"; };
3C6C7FE02B459AAA006F5CBC /* OTelSpan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTelSpan.swift; sourceTree = "<group>"; };
3C6C7FE12B459AAA006F5CBC /* OTelSpanBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTelSpanBuilder.swift; sourceTree = "<group>"; };
3C6C7FE22B459AAA006F5CBC /* OTelTraceId+Datadog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OTelTraceId+Datadog.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4622,6 +4624,7 @@
61441C902461A648003D8BB8 /* ConsoleOutputInterceptor.swift */,
61441C912461A648003D8BB8 /* UIButton+Disabling.swift */,
D2F44FC1299BD5600074B0D9 /* UIViewController+KeyboardControlling.swift */,
3C62C3602C3E852F00C7E336 /* MultiSelector.swift */,
);
path = Utils;
sourceTree = "<group>";
Expand Down Expand Up @@ -8419,6 +8422,7 @@
618236892710560900125326 /* DebugWebviewViewController.swift in Sources */,
61F74AF426F20E4600E5F5ED /* DebugCrashReportingWithRUMViewController.swift in Sources */,
1434A4662B7F8D880072E3BB /* DebugOTelTracingViewController.swift in Sources */,
3C62C3612C3E852F00C7E336 /* MultiSelector.swift in Sources */,
61E5333824B84EE2003D6C4E /* DebugRUMViewController.swift in Sources */,
61441C0524616DE9003D8BB8 /* ExampleAppDelegate.swift in Sources */,
61020C2C2758E853005EEAEA /* DebugBackgroundEventsViewController.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,32 @@ internal class DebugManualTraceInjectionViewController: UIHostingController<Debu

private var currentSession: URLSession? = nil

extension TraceContextInjection {
func toString() -> String {
switch self {
case .all:
return "All"
case .sampled:
return "Sampled"
}
}
}

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

var id: String { rawValue }
}

@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 requestURL = "https://httpbin.org/get"
@State private var selectedTraceHeaderTypes: Set<TraceHeaderType> = [.datadog, .w3c]
@State private var selectedTraceContextInjection: TraceContextInjection = .all
@State private var sampleRate: Float = 100.0
@State private var isRequestPending = false

Expand Down Expand Up @@ -59,12 +73,18 @@ internal struct DebugManualTraceInjectionView: View {
Section(header: Text("Span name:")) {
TextField("", text: $spanName)
}
Picker("Trace header type:", selection: $selectedTraceHeaderType) {
ForEach(TraceHeaderType.allCases, id: \.self) { headerType in
Text(headerType.rawValue)
Picker("Trace context injection:", selection: $selectedTraceContextInjection) {
ForEach(TraceContextInjection.allCases, id: \.self) { headerType in
Text(headerType.toString())
}
}
.pickerStyle(.inline)
MultiSelector(
label: Text("Trace header type:"),
options: TraceHeaderType.allCases,
optionToString: { $0.rawValue },
selected: $selectedTraceHeaderTypes
)
Section(header: Text("Trace sample Rate")) {
Slider(
value: $sampleRate,
Expand Down Expand Up @@ -101,42 +121,44 @@ internal struct DebugManualTraceInjectionView: View {
}

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

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

switch selectedTraceHeaderType {
case .datadog:
let writer = HTTPHeadersWriter(
samplingStrategy: .custom(sampleRate: sampleRate),
traceContextInjection: .all
)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .w3c:
let writer = W3CHTTPHeadersWriter(
samplingStrategy: .custom(sampleRate: sampleRate),
tracestate: [:],
traceContextInjection: .all
)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .b3Single:
let writer = B3HTTPHeadersWriter(
samplingStrategy: .custom(sampleRate: sampleRate),
injectEncoding: .single,
traceContextInjection: .all
)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .b3Multiple:
let writer = B3HTTPHeadersWriter(
samplingStrategy: .custom(sampleRate: sampleRate),
injectEncoding: .multiple,
traceContextInjection: .all
)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
for selectedTraceHeaderType in selectedTraceHeaderTypes {
switch selectedTraceHeaderType {
case .datadog:
let writer = HTTPHeadersWriter(
samplingStrategy: .custom(sampleRate: sampleRate),
traceContextInjection: selectedTraceContextInjection
)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .w3c:
let writer = W3CHTTPHeadersWriter(
samplingStrategy: .custom(sampleRate: sampleRate),
tracestate: [:],
traceContextInjection: selectedTraceContextInjection
)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .b3Single:
let writer = B3HTTPHeadersWriter(
samplingStrategy: .custom(sampleRate: sampleRate),
injectEncoding: .single,
traceContextInjection: selectedTraceContextInjection
)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
case .b3Multiple:
let writer = B3HTTPHeadersWriter(
samplingStrategy: .custom(sampleRate: sampleRate),
injectEncoding: .multiple,
traceContextInjection: selectedTraceContextInjection
)
Tracer.shared().inject(spanContext: span.context, writer: writer)
writer.traceHeaderFields.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }
}
}

send(request: request) {
Expand All @@ -147,7 +169,17 @@ internal struct DebugManualTraceInjectionView: View {

private func send(request: URLRequest, completion: @escaping () -> Void) {
isRequestPending = true
let task = session.dataTask(with: request) { _, _, _ in
let task = session.dataTask(with: request) { data, response, _ in
let httpResponse = response as! HTTPURLResponse
print("🚀 Request completed with status code: \(httpResponse.statusCode)")

// pretty print response
if let data = data {
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let json = json {
print("🚀 Response: \(json)")
}
}
completion()
DispatchQueue.main.async { self.isRequestPending = false }
}
Expand Down
85 changes: 85 additions & 0 deletions Datadog/Example/Utils/MultiSelector.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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

@available(iOS 14.0, *)
struct MultiSelector<LabelView: View, Selectable: Identifiable & Hashable>: View {
let label: LabelView
let options: [Selectable]
let optionToString: (Selectable) -> String

var selected: Binding<Set<Selectable>>

private var formattedSelectedListString: String {
ListFormatter.localizedString(
byJoining: selected.wrappedValue.map {
optionToString($0)
}
)
}

var body: some View {
NavigationLink(destination: multiSelectionView()) {
HStack {
label
Spacer()
Text(formattedSelectedListString)
.foregroundColor(.gray)
.multilineTextAlignment(.trailing)
}
}
}

private func multiSelectionView() -> some View {
MultiSelectionView(
options: options,
optionToString: optionToString,
selected: selected
)
}
}


@available(iOS 13.0, *)
struct MultiSelectionView<Selectable: Identifiable & Hashable>: View {
let options: [Selectable]
let optionToString: (Selectable) -> String

@Binding var selected: Set<Selectable>

var body: some View {
List {
ForEach(options) { selectable in
Button(action: {
toggleSelection(selectable: selectable)
}) {
HStack {
Text(optionToString(selectable))
.foregroundColor(.black)
Spacer()
if selected.contains(where: {
$0.id == selectable.id
}) {
Image(systemName: "checkmark")
.foregroundColor(.accentColor)
}
}
}
.tag(selectable.id)
}
}
.listStyle(GroupedListStyle())
}

private func toggleSelection(selectable: Selectable) {
if let existingIndex = selected.firstIndex(where: { $0.id == selectable.id }) {
selected.remove(at: existingIndex)
} else {
selected.insert(selectable)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import Foundation

/// Defines whether the trace context should be injected into all requests or only sampled ones.
public enum TraceContextInjection {
public enum TraceContextInjection: CaseIterable {
/// Injects trace context into all requests irrespective of the sampling decision.
case all

Expand Down

0 comments on commit d80d1cf

Please sign in to comment.