Skip to content

Commit f418abb

Browse files
committed
Recording an error may carry attributes
**Motivation:** It can be used to attach more information bout the error, like its stacktrace and similar information. This is also supported by the otel spec, so we're aligning closer with it here. **Modifications:** Change the recordError to accept optional span attributes **Result:** more powerful record error API
1 parent 499a317 commit f418abb

7 files changed

+51
-8
lines changed

Sources/Tracing/NoOpTracer.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public struct NoOpTracer: Tracer {
6060

6161
public func addEvent(_ event: SpanEvent) {}
6262

63-
public func recordError(_ error: Error) {}
63+
public func recordError(_ error: Error, attributes: SpanAttributes) {}
6464

6565
public var attributes: SpanAttributes {
6666
get {

Sources/Tracing/Span.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public protocol Span: AnyObject, _SwiftTracingSendableSpan {
4242
///
4343
/// - Parameters:
4444
/// - error: The error to be recorded.
45-
func recordError(_ error: Error)
45+
func recordError(_ error: Error, attributes: SpanAttributes)
4646

4747
/// The attributes describing this `Span`.
4848
var attributes: SpanAttributes { get set }
@@ -97,6 +97,12 @@ extension Span {
9797
}
9898
}
9999

100+
extension Span {
101+
public func recordError(_ error: Error) {
102+
self.recordError(error, attributes: [:])
103+
}
104+
}
105+
100106
// ==== ----------------------------------------------------------------------------------------------------------------
101107
// MARK: Span Event
102108

Tests/TracingTests/DynamicTracepointTracerTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ extension DynamicTracepointTestTracer {
276276
// nothing
277277
}
278278

279-
func recordError(_ error: Error) {
279+
func recordError(_ error: Error, attributes: SpanAttributes) {
280280
print("")
281281
}
282282

Tests/TracingTests/TestTracer.swift

+8-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import Tracing
2121
/// Only intended to be used in single-threaded testing.
2222
final class TestTracer: Tracer {
2323
private(set) var spans = [TestSpan]()
24-
var onEndSpan: (Span) -> Void = { _ in }
24+
var onEndSpan: (TestSpan) -> Void = { _ in }
2525

2626
func startSpan(
2727
_ operationName: String,
@@ -104,6 +104,8 @@ final class TestSpan: Span {
104104
private let startTime: DispatchWallTime
105105
private(set) var endTime: DispatchWallTime?
106106

107+
private(set) var recordedErrors: [(Error, SpanAttributes)] = []
108+
107109
let baggage: Baggage
108110

109111
private(set) var events = [SpanEvent]() {
@@ -122,14 +124,14 @@ final class TestSpan: Span {
122124

123125
private(set) var isRecording = false
124126

125-
let onEnd: (Span) -> Void
127+
let onEnd: (TestSpan) -> Void
126128

127129
init(
128130
operationName: String,
129131
startTime: DispatchWallTime,
130132
baggage: Baggage,
131133
kind: SpanKind,
132-
onEnd: @escaping (Span) -> Void
134+
onEnd: @escaping (TestSpan) -> Void
133135
) {
134136
self.operationName = operationName
135137
self.startTime = startTime
@@ -151,7 +153,9 @@ final class TestSpan: Span {
151153
self.events.append(event)
152154
}
153155

154-
func recordError(_ error: Error) {}
156+
func recordError(_ error: Error, attributes: SpanAttributes) {
157+
self.recordedErrors.append((error, attributes))
158+
}
155159

156160
func end(at time: DispatchWallTime) {
157161
self.endTime = time

Tests/TracingTests/TracedLockTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ private final class TracedLockPrintlnTracer: Tracer {
151151
self.events.append(event)
152152
}
153153

154-
func recordError(_ error: Error) {}
154+
func recordError(_ error: Error, attributes: SpanAttributes) {}
155155

156156
func end(at time: DispatchWallTime) {
157157
self.endTime = time

Tests/TracingTests/TracerTests+XCTest.swift

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extension TracerTests {
3535
("testWithSpan_automaticBaggagePropagation_async", testWithSpan_automaticBaggagePropagation_async),
3636
("testWithSpan_enterFromNonAsyncCode_passBaggage_asyncOperation", testWithSpan_enterFromNonAsyncCode_passBaggage_asyncOperation),
3737
("testWithSpan_automaticBaggagePropagation_async_throws", testWithSpan_automaticBaggagePropagation_async_throws),
38+
("testWithSpan_recordErrorWithAttributes", testWithSpan_recordErrorWithAttributes),
3839
]
3940
}
4041
}

Tests/TracingTests/TracerTests.swift

+32
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,38 @@ final class TracerTests: XCTestCase {
253253
#endif
254254
}
255255

256+
func testWithSpan_recordErrorWithAttributes() throws {
257+
#if swift(>=5.5) && canImport(_Concurrency)
258+
guard #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) else {
259+
throw XCTSkip("Task locals are not supported on this platform.")
260+
}
261+
262+
let tracer = TestTracer()
263+
InstrumentationSystem.bootstrapInternal(tracer)
264+
defer {
265+
InstrumentationSystem.bootstrapInternal(nil)
266+
}
267+
268+
var endedSpan: TestSpan? = nil
269+
tracer.onEndSpan = { span in endedSpan = span }
270+
271+
272+
let errorToThrow = ExampleSpanError()
273+
let attrsForError: SpanAttributes = ["attr": "value"]
274+
275+
tracer.withSpan("hello") { span in
276+
span.recordError(errorToThrow, attributes: attrsForError)
277+
}
278+
279+
XCTAssertTrue(endedSpan != nil)
280+
XCTAssertEqual(endedSpan!.recordedErrors.count, 1)
281+
let error = endedSpan!.recordedErrors.first!.0
282+
XCTAssertEqual(error as! ExampleSpanError, errorToThrow)
283+
let attrs = endedSpan!.recordedErrors.first!.1
284+
XCTAssertEqual(attrs, attrsForError)
285+
#endif
286+
}
287+
256288
#if swift(>=5.5) && canImport(_Concurrency)
257289
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
258290
/// Helper method to execute async operations until we can use async tests (currently incompatible with the generated LinuxMain file).

0 commit comments

Comments
 (0)