Skip to content

Commit 328d68a

Browse files
authored
Add Callback to customize Spans in URLSessionInstrumention (#340)
* Add ability to set a parent using a callback in URLSessionInstrumention, and associated tests * Convert to generic customization of spans, instead of just customizing parent
1 parent 32845f6 commit 328d68a

File tree

4 files changed

+44
-0
lines changed

4 files changed

+44
-0
lines changed

Sources/Instrumentation/URLSession/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ This behaviour can be modified or augmented by using the optional callbacks defi
1919

2020
`nameSpan: ((URLRequest) -> (String)?)?` - Modifies the name for the given request instead of stantard Opentelemetry name
2121

22+
`spanCustomization: ((URLRequest, SpanBuilder) -> Void)?` - Customizes the span while it's being built, such as by adding a parent, a link, attributes, etc.
23+
2224
`createdRequest: ((URLRequest, Span) -> Void)?` - Called after request is created, it allows to add extra information to the Span
2325

2426
`receivedResponse: ((URLResponse, DataOrFile?, Span) -> Void)?`- Called after response is received, it allows to add extra information to the Span

Sources/Instrumentation/URLSession/URLSessionInstrumentationConfiguration.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public struct URLSessionInstrumentationConfiguration {
1515
public init(shouldRecordPayload: ((URLSession) -> (Bool)?)? = nil,
1616
shouldInstrument: ((URLRequest) -> (Bool)?)? = nil,
1717
nameSpan: ((URLRequest) -> (String)?)? = nil,
18+
spanCustomization: ((URLRequest, SpanBuilder) -> Void)? = nil,
1819
shouldInjectTracingHeaders: ((URLRequest) -> (Bool)?)? = nil,
1920
injectCustomHeaders: ((inout URLRequest, Span?) -> Void)? = nil,
2021
createdRequest: ((URLRequest, Span) -> Void)? = nil,
@@ -26,6 +27,7 @@ public struct URLSessionInstrumentationConfiguration {
2627
self.shouldInjectTracingHeaders = shouldInjectTracingHeaders
2728
self.injectCustomHeaders = injectCustomHeaders
2829
self.nameSpan = nameSpan
30+
self.spanCustomization = spanCustomization
2931
self.createdRequest = createdRequest
3032
self.receivedResponse = receivedResponse
3133
self.receivedError = receivedError
@@ -52,6 +54,9 @@ public struct URLSessionInstrumentationConfiguration {
5254
/// default name: `HTTP {method}` e.g. `HTTP PUT`
5355
public var nameSpan: ((URLRequest) -> (String)?)?
5456

57+
/// Implement this callback to customize the span, such as by adding a parent, a link, attributes, etc
58+
public var spanCustomization: ((URLRequest, SpanBuilder) -> Void)?
59+
5560
/// Called before the span is created, it allows to add extra information to the Span
5661
public var createdRequest: ((URLRequest, Span) -> Void)?
5762

Sources/Instrumentation/URLSession/URLSessionLogger.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class URLSessionLogger {
7171
attributes.forEach {
7272
spanBuilder.setAttribute(key: $0.key, value: $0.value)
7373
}
74+
instrumentation.configuration.spanCustomization?(request, spanBuilder)
7475

7576
let span = spanBuilder.startSpan()
7677
runningSpansQueue.sync {

Tests/InstrumentationTests/URLSessionTests/URLSessionInstrumentationTests.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class URLSessionInstrumentationTests: XCTestCase {
1313
public var shouldRecordPayloadCalled: Bool = false
1414
public var shouldInstrumentCalled: Bool = false
1515
public var nameSpanCalled: Bool = false
16+
public var spanCustomizationCalled: Bool = false
1617
public var shouldInjectTracingHeadersCalled: Bool = false
1718
public var createdRequestCalled: Bool = false
1819
public var receivedResponseCalled: Bool = false
@@ -54,6 +55,12 @@ class URLSessionInstrumentationTests: XCTestCase {
5455
}
5556
return "new name"
5657
},
58+
spanCustomization: { req, spanBuilder in
59+
checker.spanCustomizationCalled = true
60+
if !(req.url?.host?.contains("defaultName") ?? false) {
61+
spanBuilder.setSpanKind(spanKind: .consumer)
62+
}
63+
},
5764
shouldInjectTracingHeaders: { _ in
5865
checker.shouldInjectTracingHeadersCalled = true
5966
return true
@@ -138,6 +145,32 @@ class URLSessionInstrumentationTests: XCTestCase {
138145
}
139146
}
140147

148+
public func testOverrideSpanCustomization() {
149+
let request = URLRequest(url: URL(string: "http://google.com")!)
150+
151+
URLSessionLogger.processAndLogRequest(request, sessionTaskId: "id", instrumentation: URLSessionInstrumentationTests.instrumentation, shouldInjectHeaders: true)
152+
153+
XCTAssertTrue(URLSessionInstrumentationTests.checker.spanCustomizationCalled)
154+
155+
XCTAssertEqual(1, URLSessionLogger.runningSpans.count)
156+
XCTAssertNotNil(URLSessionLogger.runningSpans["id"])
157+
if let span = URLSessionLogger.runningSpans["id"] {
158+
XCTAssertEqual(SpanKind.consumer, span.kind)
159+
}
160+
}
161+
162+
public func testDefaultSpanCustomization() {
163+
let request = URLRequest(url: URL(string: "http://defaultName.com")!)
164+
165+
URLSessionLogger.processAndLogRequest(request, sessionTaskId: "id", instrumentation: URLSessionInstrumentationTests.instrumentation, shouldInjectHeaders: true)
166+
167+
XCTAssertEqual(1, URLSessionLogger.runningSpans.count)
168+
XCTAssertNotNil(URLSessionLogger.runningSpans["id"])
169+
if let span = URLSessionLogger.runningSpans["id"] {
170+
XCTAssertEqual(SpanKind.client, span.kind)
171+
}
172+
}
173+
141174
public func testConfigurationCallbacksCalledWhenSuccess() {
142175
let request = URLRequest(url: URL(string: "http://localhost:33333/success")!)
143176

@@ -154,6 +187,7 @@ class URLSessionInstrumentationTests: XCTestCase {
154187

155188
XCTAssertTrue(URLSessionInstrumentationTests.checker.shouldInstrumentCalled)
156189
XCTAssertTrue(URLSessionInstrumentationTests.checker.nameSpanCalled)
190+
XCTAssertTrue(URLSessionInstrumentationTests.checker.spanCustomizationCalled)
157191
XCTAssertTrue(URLSessionInstrumentationTests.checker.shouldInjectTracingHeadersCalled)
158192
XCTAssertTrue(URLSessionInstrumentationTests.checker.createdRequestCalled)
159193
XCTAssertTrue(URLSessionInstrumentationTests.checker.receivedResponseCalled)
@@ -174,6 +208,7 @@ class URLSessionInstrumentationTests: XCTestCase {
174208

175209
XCTAssertTrue(URLSessionInstrumentationTests.checker.shouldInstrumentCalled)
176210
XCTAssertTrue(URLSessionInstrumentationTests.checker.nameSpanCalled)
211+
XCTAssertTrue(URLSessionInstrumentationTests.checker.spanCustomizationCalled)
177212
XCTAssertTrue(URLSessionInstrumentationTests.checker.shouldInjectTracingHeadersCalled)
178213
XCTAssertTrue(URLSessionInstrumentationTests.checker.createdRequestCalled)
179214
XCTAssertTrue(URLSessionInstrumentationTests.checker.receivedResponseCalled)
@@ -193,6 +228,7 @@ class URLSessionInstrumentationTests: XCTestCase {
193228

194229
XCTAssertTrue(URLSessionInstrumentationTests.checker.shouldInstrumentCalled)
195230
XCTAssertTrue(URLSessionInstrumentationTests.checker.nameSpanCalled)
231+
XCTAssertTrue(URLSessionInstrumentationTests.checker.spanCustomizationCalled)
196232
XCTAssertTrue(URLSessionInstrumentationTests.checker.shouldInjectTracingHeadersCalled)
197233
XCTAssertTrue(URLSessionInstrumentationTests.checker.createdRequestCalled)
198234
XCTAssertFalse(URLSessionInstrumentationTests.checker.receivedResponseCalled)

0 commit comments

Comments
 (0)