Closed cszatmary closed 11 months ago
Quoting from https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/dd_libraries/ios/?tab=cocoapods
In order for the SDK to automatically trace all network requests made to the given hosts, specify the firstPartyHosts array in the Datadog initialization, enable URLSessionInstrumentation for your delegate type and pass the delegate instance to the URLSession:
This delegate type must come from your application/library code that you need to conform.
Is there an example you can share of what this custom delegate type should look like? I'm not clear on what the implementation needs to be in order to make it work with automatic tracing.
Case number 1
I assume that you don't use any concrete SessionDelegate
for your own purposes. In this case you need to create an empty object like
final class MyCustomSessionDelegate: NSObject, URLSessionDataDelegate { }
then use it in Datadog init
URLSessionInstrumentation.enable(
with: .init(
delegateClass: MyCustomSessionDelegate.self,
)
)
and in each place where you use/create URLSession instance use your delegate like
let session = URLSession(
configuration: .default,
delegate: MyCustomSessionDelegate(),
delegateQueue: nil
)
Case number 2 When you need to handle custom logic for session delegates e.g. socket connection or ssl pinning. I use next
final class MyCustomSessionDelegate: NSObject, URLSessionDataDelegate {
private let mySessionDelegate: URLSessionDelegate
init(with sessionDelegate: URLSessionDelegate) {
self. sessionDelegate = sessionDelegate
}
}
extension MyCustomSessionDelegate: URLSessionWebSocketDelegate {
func urlSession(
_ session: URLSession,
webSocketTask: URLSessionWebSocketTask,
didOpenWithProtocol protocol: String?
) {
if let sessionDelegate = self.sessionDelegate as? URLSessionWebSocketDelegate {
sessionDelegate.urlSession?(
session,
webSocketTask: webSocketTask,
didOpenWithProtocol: `protocol`
)
}
}
func urlSession(
_ session: URLSession,
webSocketTask: URLSessionWebSocketTask,
didCloseWith closeCode: URLSessionWebSocketTask.CloseCode,
reason: Data?
) {
if let sessionDelegate = self.sessionDelegate as? URLSessionWebSocketDelegate {
sessionDelegate.urlSession?(
session,
webSocketTask: webSocketTask,
didCloseWith: closeCode,
reason: reason
)
}
}
}
where you either conform your class
to URLSessionWebSocketDelegate
or create separate object of such delegate.
and in case of conformance
class MyClass: URLSessionWebSocketDelegate {
let session = URLSession(
configuration: .default,
delegate: MyCustomSessionDelegate(with: self),
delegateQueue: nil
)
}
@cszatmary Hope it will help.
Thanks so much @ambrusha, this is exactly what I was looking for! I just tried Case 1 and it worked, I've verified traces are showing up in DD. I wasn't sure if I need to implement any of the delegate methods with any specific logic, but looks like an empty class works just fine.
thanks @ambrusha for exhaustive example, closing it.
Hi
I tired creating the sample below. I see only the trace related to span are getting logged. If i comment the span nothing is getting traced in datadog. I have set the custom delegate. What am i missing ? Please help. final class CustomDelegate: NSObject, URLSessionDataDelegate { }
private func setupTrace() {
Trace.enable(
with: Trace.Configuration(sampleRate: 100,
service: "ios-app",
urlSessionTracking: Trace.Configuration.URLSessionTracking(
firstPartyHostsTracing: .trace(hosts: ["jsonplaceholder.typicode.com"])
),
networkInfoEnabled: true
)
)
self.setupURLSessionTrace()
}
private func setupSessionReplay() {
SessionReplay.enable(
with: SessionReplay.Configuration(
replaySampleRate: 100
)
)
}
private func setupURLSessionTrace() {
URLSessionInstrumentation.enable(
with: .init(
delegateClass: CustomDelegate.self
)
)
}
class TodoService {
let session = URLSession(
configuration: .default,
delegate: CustomDelegate(),
delegateQueue: nil
)
private let baseURL = URL(string: "https://jsonplaceholder.typicode.com/todos")!
func fetchTodos() -> AnyPublisher<[Todo], Error> {
session.dataTaskPublisher(for: baseURL)
.map(\.data)
.decode(type: [Todo].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
}
struct Todo: Decodable {
let id: Int
let title: String
let completed: Bool
}
final class CustomDelegate: NSObject, URLSessionDataDelegate { }
class TodoViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
private let todoService = TodoService()
@Published var todos: [Todo] = []
func fetchTodos() {
let tracer = Tracer.shared().startSpan(operationName: "Demo API", tags: ["Sample":"Sample"])
todoService.fetchTodos()
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { _ in }) { todos in
tracer.finish()
self.todos = todos
}
.store(in: &cancellables)
}
}
The thing
I'm setting up the DD SDK on my company's iOS app. I'm following the documentation for enabling tracing here: https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/dd_libraries/ios/?tab=cocoapods
It has this code snippet for setting up automatically tracing HTTP requests:
I'm confused as to what should be used for the
delegate
. There is no such thing asSessionDelegate
so I assume this must be a placeholder? (This was not clear at first). Does the SDK provide a delegate that can be used out of the box or do I have to define my own? I noticed there is theDatadogURLSessionDelegate
type however it is deprecated.If I need to create my own custom delegate implementation is there any documentation on what needs to be implemented in order to make it work with this SDK?