Skip to content

Mark types Sendable #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions Sources/Instrumentation/Instrument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@

import InstrumentationBaggage

/// Typealias used to simplify Support of old Swift versions which do not have `Sendable` defined.
#if swift(>=5.6.0)
@preconcurrency public protocol _SwiftInstrumentationSendable: Sendable {}
#else
public protocol _SwiftInstrumentationSendable {}
#endif

/// Conforming types are used to extract values from a specific `Carrier`.
public protocol Extractor {
public protocol Extractor: _SwiftInstrumentationSendable {
/// The carrier to extract values from.
associatedtype Carrier

Expand All @@ -28,7 +35,7 @@ public protocol Extractor {
}

/// Conforming types are used to inject values into a specific `Carrier`.
public protocol Injector {
public protocol Injector: _SwiftInstrumentationSendable {
/// The carrier to inject values into.
associatedtype Carrier

Expand All @@ -43,7 +50,7 @@ public protocol Injector {

/// Conforming types are usually cross-cutting tools like tracers. They are agnostic of what specific `Carrier` is used
/// to propagate metadata across boundaries, but instead just specify what values to use for which keys.
public protocol Instrument {
public protocol Instrument: _SwiftInstrumentationSendable {
/// Extract values from a `Carrier` by using the given extractor and inject them into the given `Baggage`.
/// It's quite common for `Instrument`s to come up with new values if they weren't passed along in the given `Carrier`.
///
Expand Down
44 changes: 38 additions & 6 deletions Sources/Tracing/Span.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
//
//===----------------------------------------------------------------------===//

import Dispatch
#if swift(>=5.6.0)
@preconcurrency import struct Dispatch.DispatchWallTime
#else
import struct Dispatch.DispatchWallTime
#endif
@_exported import InstrumentationBaggage

/// A `Span` represents an interval from the start of an operation to its end, along with additional metadata included
Expand All @@ -22,7 +26,7 @@ import Dispatch
/// Creating a `Span` is delegated to a ``Tracer`` and end users should never create them directly.
///
/// - 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.
public protocol Span: AnyObject {
public protocol Span: AnyObject, _SwiftTracingSendableSpan {
/// The read-only `Baggage` of this `Span`, set when starting this `Span`.
var baggage: Baggage { get }

Expand Down Expand Up @@ -233,8 +237,13 @@ public enum SpanAttribute: Equatable {
case string(String)
case stringArray([String])

#if swift(>=5.6)
case stringConvertible(CustomStringConvertible & Sendable)
case stringConvertibleArray([CustomStringConvertible & Sendable])
#else
case stringConvertible(CustomStringConvertible)
case stringConvertibleArray([CustomStringConvertible])
#endif

#if swift(>=5.2)
// older swifts get confused and can't resolve if we mean the `case int(Int64)` or any of those overloads
Expand Down Expand Up @@ -383,11 +392,18 @@ extension Array: SpanAttributeConvertible where Element: SpanAttributeConvertibl
return .boolArray(value)
} else if let value = self as? [String] {
return .stringArray(value)
} else if let value = self as? [CustomStringConvertible] {
}
#if swift(>=5.6.0)
if let value = self as? [CustomStringConvertible & Sendable] {
return .stringConvertibleArray(value)
}
#else
if let value = self as? [CustomStringConvertible] {
return .stringConvertibleArray(value)
} else {
fatalError("Not supported SpanAttribute array type: \(type(of: self))")
}
#endif

fatalError("Not supported SpanAttribute array type: \(type(of: self))")
}
}

Expand Down Expand Up @@ -650,10 +666,26 @@ public struct SpanLink {

/// Create a new `SpanLink`.
/// - Parameters:
/// - context: The `Baggage` identifying the targeted ``Span``.
/// - baggage: The `Baggage` identifying the targeted ``Span``.
/// - attributes: ``SpanAttributes`` that further describe the link. Defaults to no attributes.
public init(baggage: Baggage, attributes: SpanAttributes = [:]) {
self.baggage = baggage
self.attributes = attributes
}
}

#if compiler(>=5.6)
@preconcurrency public protocol _SwiftTracingSendableSpan: Sendable {}
#else
public protocol _SwiftTracingSendableSpan {}
#endif

#if compiler(>=5.6)
extension SpanAttributes: Sendable {}
extension SpanAttribute: Sendable {} // @unchecked because some payloads are CustomStringConvertible
extension SpanStatus: Sendable {}
extension SpanEvent: Sendable {}
extension SpanKind: Sendable {}
extension SpanStatus.Code: Sendable {}
extension SpanLink: Sendable {}
#endif
2 changes: 1 addition & 1 deletion Sources/Tracing/Tracer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public protocol Tracer: Instrument {
/// - operationName: The name of the operation being traced. This may be a handler function, database call, ...
/// - baggage: The `Baggage` providing information on where to start the new ``Span``.
/// - kind: The ``SpanKind`` of the new ``Span``.
/// - time: The `DispatchTime` at which to start the new ``Span``.
/// - time: The time at which to start the new ``Span``.
/// - function: The function name in which the span was started
/// - fileID: The `fileID` where the span was started.
/// - line: The file line where the span was started.
Expand Down
7 changes: 7 additions & 0 deletions Tests/TracingTests/DynamicTracepointTracerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ final class DynamicTracepointTracerTests: XCTestCase {
}
}

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

Expand Down Expand Up @@ -227,6 +228,7 @@ final class DynamicTracepointTestTracer: Tracer {
}

extension DynamicTracepointTestTracer {
/// Only intended to be used in single-threaded testing.
final class TracepointSpan: Tracing.Span {
private let operationName: String
private let kind: SpanKind
Expand Down Expand Up @@ -288,3 +290,8 @@ extension DynamicTracepointTestTracer {
}
}
}

#if compiler(>=5.6.0)
extension DynamicTracepointTestTracer: @unchecked Sendable {} // only intended for single threaded testing
extension DynamicTracepointTestTracer.TracepointSpan: @unchecked Sendable {} // only intended for single threaded testing
#endif
8 changes: 7 additions & 1 deletion Tests/TracingTests/SpanTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ public struct HTTPAttributes: SpanAttributeNamespace {
}
}

public struct CustomAttributeValue: Equatable, CustomStringConvertible, SpanAttributeConvertible {
public struct CustomAttributeValue: Equatable, _CustomAttributeValueSendable, CustomStringConvertible, SpanAttributeConvertible {
public func toSpanAttribute() -> SpanAttribute {
.stringConvertible(self)
}
Expand All @@ -255,6 +255,12 @@ public struct CustomAttributeValue: Equatable, CustomStringConvertible, SpanAttr
}
#endif

#if swift(>=5.6.0)
typealias _CustomAttributeValueSendable = Sendable
#else
typealias _CustomAttributeValueSendable = Any
#endif

private struct TestBaggageContextKey: BaggageKey {
typealias Value = String
}
7 changes: 7 additions & 0 deletions Tests/TracingTests/TestTracer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Instrumentation
import InstrumentationBaggage
import Tracing

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

/// Only intended to be used in single-threaded testing.
final class TestSpan: Span {
private let operationName: String
private let kind: SpanKind
Expand Down Expand Up @@ -156,3 +158,8 @@ final class TestSpan: Span {
self.onEnd(self)
}
}

#if compiler(>=5.6.0)
extension TestTracer: @unchecked Sendable {} // only intended for single threaded testing
extension TestSpan: @unchecked Sendable {} // only intended for single threaded testing
#endif
6 changes: 6 additions & 0 deletions Tests/TracingTests/TracedLockTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ enum TaskIDKey: BaggageKey {
// ==== ------------------------------------------------------------------------
// MARK: PrintLn Tracer

/// Only intended to be used in single-threaded testing.
private final class TracedLockPrintlnTracer: Tracer {
func startSpan(
_ operationName: String,
Expand Down Expand Up @@ -158,3 +159,8 @@ private final class TracedLockPrintlnTracer: Tracer {
}
}
}

#if compiler(>=5.6.0)
extension TracedLockPrintlnTracer: Sendable {}
extension TracedLockPrintlnTracer.TracedLockPrintlnSpan: @unchecked Sendable {} // only intended for single threaded testing
#endif