Skip to content

Commit 1aff1f1

Browse files
authored
Mark types Sendable (#83)
1 parent 1eb0a48 commit 1aff1f1

File tree

7 files changed

+76
-11
lines changed

7 files changed

+76
-11
lines changed

Sources/Instrumentation/Instrument.swift

+10-3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@
1414

1515
import InstrumentationBaggage
1616

17+
/// Typealias used to simplify Support of old Swift versions which do not have `Sendable` defined.
18+
#if swift(>=5.6.0)
19+
@preconcurrency public protocol _SwiftInstrumentationSendable: Sendable {}
20+
#else
21+
public protocol _SwiftInstrumentationSendable {}
22+
#endif
23+
1724
/// Conforming types are used to extract values from a specific `Carrier`.
18-
public protocol Extractor {
25+
public protocol Extractor: _SwiftInstrumentationSendable {
1926
/// The carrier to extract values from.
2027
associatedtype Carrier
2128

@@ -28,7 +35,7 @@ public protocol Extractor {
2835
}
2936

3037
/// Conforming types are used to inject values into a specific `Carrier`.
31-
public protocol Injector {
38+
public protocol Injector: _SwiftInstrumentationSendable {
3239
/// The carrier to inject values into.
3340
associatedtype Carrier
3441

@@ -43,7 +50,7 @@ public protocol Injector {
4350

4451
/// Conforming types are usually cross-cutting tools like tracers. They are agnostic of what specific `Carrier` is used
4552
/// to propagate metadata across boundaries, but instead just specify what values to use for which keys.
46-
public protocol Instrument {
53+
public protocol Instrument: _SwiftInstrumentationSendable {
4754
/// Extract values from a `Carrier` by using the given extractor and inject them into the given `Baggage`.
4855
/// It's quite common for `Instrument`s to come up with new values if they weren't passed along in the given `Carrier`.
4956
///

Sources/Tracing/Span.swift

+38-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
import Dispatch
15+
#if swift(>=5.6.0)
16+
@preconcurrency import struct Dispatch.DispatchWallTime
17+
#else
18+
import struct Dispatch.DispatchWallTime
19+
#endif
1620
@_exported import InstrumentationBaggage
1721

1822
/// A `Span` represents an interval from the start of an operation to its end, along with additional metadata included
@@ -22,7 +26,7 @@ import Dispatch
2226
/// Creating a `Span` is delegated to a ``Tracer`` and end users should never create them directly.
2327
///
2428
/// - SeeAlso: For more details refer to the [OpenTelemetry Specification: Span](https://github.com/open-telemetry/opentelemetry-specification/blob/v0.7.0/specification/trace/api.md#span) which this type is compatible with.
25-
public protocol Span: AnyObject {
29+
public protocol Span: AnyObject, _SwiftTracingSendableSpan {
2630
/// The read-only `Baggage` of this `Span`, set when starting this `Span`.
2731
var baggage: Baggage { get }
2832

@@ -233,8 +237,13 @@ public enum SpanAttribute: Equatable {
233237
case string(String)
234238
case stringArray([String])
235239

240+
#if swift(>=5.6)
241+
case stringConvertible(CustomStringConvertible & Sendable)
242+
case stringConvertibleArray([CustomStringConvertible & Sendable])
243+
#else
236244
case stringConvertible(CustomStringConvertible)
237245
case stringConvertibleArray([CustomStringConvertible])
246+
#endif
238247

239248
#if swift(>=5.2)
240249
// older swifts get confused and can't resolve if we mean the `case int(Int64)` or any of those overloads
@@ -383,11 +392,18 @@ extension Array: SpanAttributeConvertible where Element: SpanAttributeConvertibl
383392
return .boolArray(value)
384393
} else if let value = self as? [String] {
385394
return .stringArray(value)
386-
} else if let value = self as? [CustomStringConvertible] {
395+
}
396+
#if swift(>=5.6.0)
397+
if let value = self as? [CustomStringConvertible & Sendable] {
398+
return .stringConvertibleArray(value)
399+
}
400+
#else
401+
if let value = self as? [CustomStringConvertible] {
387402
return .stringConvertibleArray(value)
388-
} else {
389-
fatalError("Not supported SpanAttribute array type: \(type(of: self))")
390403
}
404+
#endif
405+
406+
fatalError("Not supported SpanAttribute array type: \(type(of: self))")
391407
}
392408
}
393409

@@ -650,10 +666,26 @@ public struct SpanLink {
650666

651667
/// Create a new `SpanLink`.
652668
/// - Parameters:
653-
/// - context: The `Baggage` identifying the targeted ``Span``.
669+
/// - baggage: The `Baggage` identifying the targeted ``Span``.
654670
/// - attributes: ``SpanAttributes`` that further describe the link. Defaults to no attributes.
655671
public init(baggage: Baggage, attributes: SpanAttributes = [:]) {
656672
self.baggage = baggage
657673
self.attributes = attributes
658674
}
659675
}
676+
677+
#if compiler(>=5.6)
678+
@preconcurrency public protocol _SwiftTracingSendableSpan: Sendable {}
679+
#else
680+
public protocol _SwiftTracingSendableSpan {}
681+
#endif
682+
683+
#if compiler(>=5.6)
684+
extension SpanAttributes: Sendable {}
685+
extension SpanAttribute: Sendable {} // @unchecked because some payloads are CustomStringConvertible
686+
extension SpanStatus: Sendable {}
687+
extension SpanEvent: Sendable {}
688+
extension SpanKind: Sendable {}
689+
extension SpanStatus.Code: Sendable {}
690+
extension SpanLink: Sendable {}
691+
#endif

Sources/Tracing/Tracer.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public protocol Tracer: Instrument {
2929
/// - operationName: The name of the operation being traced. This may be a handler function, database call, ...
3030
/// - baggage: The `Baggage` providing information on where to start the new ``Span``.
3131
/// - kind: The ``SpanKind`` of the new ``Span``.
32-
/// - time: The `DispatchTime` at which to start the new ``Span``.
32+
/// - time: The time at which to start the new ``Span``.
3333
/// - function: The function name in which the span was started
3434
/// - fileID: The `fileID` where the span was started.
3535
/// - line: The file line where the span was started.

Tests/TracingTests/DynamicTracepointTracerTests.swift

+7
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ final class DynamicTracepointTracerTests: XCTestCase {
104104
}
105105
}
106106

107+
/// Only intended to be used in single-threaded testing.
107108
final class DynamicTracepointTestTracer: Tracer {
108109
private(set) var activeTracepoints: Set<TracepointID> = []
109110

@@ -227,6 +228,7 @@ final class DynamicTracepointTestTracer: Tracer {
227228
}
228229

229230
extension DynamicTracepointTestTracer {
231+
/// Only intended to be used in single-threaded testing.
230232
final class TracepointSpan: Tracing.Span {
231233
private let operationName: String
232234
private let kind: SpanKind
@@ -288,3 +290,8 @@ extension DynamicTracepointTestTracer {
288290
}
289291
}
290292
}
293+
294+
#if compiler(>=5.6.0)
295+
extension DynamicTracepointTestTracer: @unchecked Sendable {} // only intended for single threaded testing
296+
extension DynamicTracepointTestTracer.TracepointSpan: @unchecked Sendable {} // only intended for single threaded testing
297+
#endif

Tests/TracingTests/SpanTests.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ public struct HTTPAttributes: SpanAttributeNamespace {
244244
}
245245
}
246246

247-
public struct CustomAttributeValue: Equatable, CustomStringConvertible, SpanAttributeConvertible {
247+
public struct CustomAttributeValue: Equatable, _CustomAttributeValueSendable, CustomStringConvertible, SpanAttributeConvertible {
248248
public func toSpanAttribute() -> SpanAttribute {
249249
.stringConvertible(self)
250250
}
@@ -255,6 +255,12 @@ public struct CustomAttributeValue: Equatable, CustomStringConvertible, SpanAttr
255255
}
256256
#endif
257257

258+
#if swift(>=5.6.0)
259+
typealias _CustomAttributeValueSendable = Sendable
260+
#else
261+
typealias _CustomAttributeValueSendable = Any
262+
#endif
263+
258264
private struct TestBaggageContextKey: BaggageKey {
259265
typealias Value = String
260266
}

Tests/TracingTests/TestTracer.swift

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import Instrumentation
1818
import InstrumentationBaggage
1919
import Tracing
2020

21+
/// Only intended to be used in single-threaded testing.
2122
final class TestTracer: Tracer {
2223
private(set) var spans = [TestSpan]()
2324
var onEndSpan: (Span) -> Void = { _ in }
@@ -93,6 +94,7 @@ extension Baggage {
9394
}
9495
}
9596

97+
/// Only intended to be used in single-threaded testing.
9698
final class TestSpan: Span {
9799
private let operationName: String
98100
private let kind: SpanKind
@@ -156,3 +158,8 @@ final class TestSpan: Span {
156158
self.onEnd(self)
157159
}
158160
}
161+
162+
#if compiler(>=5.6.0)
163+
extension TestTracer: @unchecked Sendable {} // only intended for single threaded testing
164+
extension TestSpan: @unchecked Sendable {} // only intended for single threaded testing
165+
#endif

Tests/TracingTests/TracedLockTests.swift

+6
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ enum TaskIDKey: BaggageKey {
5858
// ==== ------------------------------------------------------------------------
5959
// MARK: PrintLn Tracer
6060

61+
/// Only intended to be used in single-threaded testing.
6162
private final class TracedLockPrintlnTracer: Tracer {
6263
func startSpan(
6364
_ operationName: String,
@@ -158,3 +159,8 @@ private final class TracedLockPrintlnTracer: Tracer {
158159
}
159160
}
160161
}
162+
163+
#if compiler(>=5.6.0)
164+
extension TracedLockPrintlnTracer: Sendable {}
165+
extension TracedLockPrintlnTracer.TracedLockPrintlnSpan: @unchecked Sendable {} // only intended for single threaded testing
166+
#endif

0 commit comments

Comments
 (0)