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 1 commit
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
21 changes: 18 additions & 3 deletions Sources/Instrumentation/Instrument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,21 @@

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.
#if swift(>=5.6.0)
associatedtype Carrier: Sendable
#else
associatedtype Carrier
#endif

/// Extract the value for the given key from the `Carrier`.
///
Expand All @@ -28,9 +39,13 @@ 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.
#if swift(>=5.6.0)
associatedtype Carrier: Sendable
#else
associatedtype Carrier
#endif

/// Inject the given value for the given key into the given `Carrier`.
///
Expand All @@ -43,7 +58,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
20 changes: 18 additions & 2 deletions Sources/Tracing/Span.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,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 @@ -650,10 +650,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: @unchecked Sendable {}
extension SpanStatus: Sendable {}
extension SpanEvent: @unchecked Sendable {} // unchecked because of DispatchWallTime
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is DispatchWallTime used for locking?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, for the "wall time" time type. Swift's Clocks are missing functionality and we would have to require 5.7 so sadly it's a no go either way... Though I'm still looking into using Swift's clock types

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but why is it "unchecked because of DispatchWallTime"? Is DispatchWallTime not marked as Sendable? Shouldn't we use @preconcurrency in that case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I just moved to that in e3c5bc1 (#83) :)

extension SpanKind: Sendable {}
extension SpanStatus.Code: Sendable {}
extension SpanLink: Sendable {}
#endif
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 {}
extension DynamicTracepointTestTracer.TracepointSpan: @unchecked Sendable {}
#endif
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 {}
extension TestSpan: @unchecked Sendable {}
#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 {}
#endif