diff --git a/Package.swift b/Package.swift index 5cd1b0f..bfdd593 100644 --- a/Package.swift +++ b/Package.swift @@ -8,7 +8,7 @@ let package = Package( .library(name: "Tracing", targets: ["Tracing"]), ], dependencies: [ - .package(url: "https://github.com/apple/swift-service-context.git", from: "1.0.0"), + .package(url: "https://github.com/apple/swift-service-context.git", from: "1.1.0"), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), ], targets: [ diff --git a/Sources/Tracing/Tracer.swift b/Sources/Tracing/Tracer.swift index e3ca14c..988ff4d 100644 --- a/Sources/Tracing/Tracer.swift +++ b/Sources/Tracing/Tracer.swift @@ -315,12 +315,42 @@ public func withSpan( /// - instant: the time instant at which the span started /// - context: The `ServiceContext` providing information on where to start the new ``Span``. /// - kind: The ``SpanKind`` of the new ``Span``. +/// - isolation: Defaulted parameter for inheriting isolation of calling actor /// - 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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) +#if swift(>=6.0) +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal ServiceContext +public func withSpan( + _ operationName: String, + at instant: @autoclosure () -> Instant, + context: @autoclosure () -> ServiceContext = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + isolation: isolated(any Actor)? = #isolation, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Span) async throws -> T +) async rethrows -> T { + try await InstrumentationSystem.legacyTracer.withAnySpan( + operationName, + at: instant(), + context: context(), + ofKind: kind, + function: function, + file: fileID, + line: line + ) { anySpan in + try await operation(anySpan) + } +} +#endif + +@_disfavoredOverload +@available(*, deprecated, message: "Prefer #isolation version of this API") @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal ServiceContext public func withSpan( _ operationName: String, @@ -360,13 +390,42 @@ public func withSpan( /// - Parameters: /// - operationName: The name of the operation being traced. This may be a handler function, database call, ... /// - context: The `ServiceContext` providing information on where to start the new ``Span``. -/// - kind: The ``SpanKind`` of the new ``Span``. +/// - ofKind: The ``SpanKind`` of the new ``Span``. +/// - isolation: Defaulted parameter for inheriting isolation of calling actor /// - 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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) +#if swift(>=6.0) +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal ServiceContext +public func withSpan( + _ operationName: String, + context: @autoclosure () -> ServiceContext = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + isolation: isolated(any Actor)? = #isolation, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Span) async throws -> T +) async rethrows -> T { + try await InstrumentationSystem.legacyTracer.withAnySpan( + operationName, + at: DefaultTracerClock.now, + context: context(), + ofKind: kind, + function: function, + file: fileID, + line: line + ) { anySpan in + try await operation(anySpan) + } +} +#endif + +@_disfavoredOverload +@available(*, deprecated, message: "Prefer #isolation version of this API") @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal ServiceContext public func withSpan( _ operationName: String, @@ -407,12 +466,42 @@ public func withSpan( /// - context: The `ServiceContext` providing information on where to start the new ``Span``. /// - kind: The ``SpanKind`` of the new ``Span``. /// - instant: the time instant at which the span started +/// - isolation: Defaulted parameter for inheriting isolation of calling actor /// - 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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) +#if swift(>=6.0) +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public func withSpan( + _ operationName: String, + context: @autoclosure () -> ServiceContext = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at instant: @autoclosure () -> some TracerInstant = DefaultTracerClock.now, + isolation: isolated(any Actor)? = #isolation, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Span) async throws -> T +) async rethrows -> T { + try await InstrumentationSystem.legacyTracer.withAnySpan( + operationName, + at: instant(), + context: context(), + ofKind: kind, + function: function, + file: fileID, + line: line + ) { anySpan in + try await operation(anySpan) + } +} +#endif + +@_disfavoredOverload +@available(*, deprecated, message: "Prefer #isolation version of this API") @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) public func withSpan( _ operationName: String, diff --git a/Sources/Tracing/TracerProtocol+Legacy.swift b/Sources/Tracing/TracerProtocol+Legacy.swift index 3c07976..4258fe6 100644 --- a/Sources/Tracing/TracerProtocol+Legacy.swift +++ b/Sources/Tracing/TracerProtocol+Legacy.swift @@ -300,12 +300,48 @@ extension LegacyTracer { /// - operationName: The name of the operation being traced. This may be a handler function, database call, ... /// - context: The `ServiceContext` providing information on where to start the new ``Span``. /// - kind: The ``SpanKind`` of the new ``Span``. + /// - isolation: Defaulted parameter for inheriting isolation of calling actor /// - 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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) + #if swift(>=6.0) + public func withAnySpan( + _ operationName: String, + at instant: @autoclosure () -> Instant, + context: @autoclosure () -> ServiceContext = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + isolation: isolated(any Actor)? = #isolation, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Tracing.Span) async throws -> T + ) async rethrows -> T { + let span = self.startAnySpan( + operationName, + at: instant(), + context: context(), + ofKind: kind, + function: function, + file: fileID, + line: line + ) + defer { span.end() } + do { + return try await ServiceContext.$current.withValue(span.context) { + try await operation(span) + } + } catch { + span.recordError(error) + throw error // rethrow + } + } + #endif + + @_disfavoredOverload + @available(*, deprecated, message: "Prefer #isolation version of this API") public func withAnySpan( _ operationName: String, at instant: @autoclosure () -> Instant, @@ -354,12 +390,47 @@ extension LegacyTracer { /// - operationName: The name of the operation being traced. This may be a handler function, database call, ... /// - context: The `ServiceContext` providing information on where to start the new ``Span``. /// - kind: The ``SpanKind`` of the new ``Span``. + /// - isolation: Defaulted parameter for inheriting isolation of calling actor /// - 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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) + #if swift(>=6.0) + public func withAnySpan( + _ operationName: String, + context: @autoclosure () -> ServiceContext = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + isolation: (any Actor)? = #isolation, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Tracing.Span) async throws -> T + ) async rethrows -> T { + let span = self.startAnySpan( + operationName, + at: DefaultTracerClock.now, + context: context(), + ofKind: kind, + function: function, + file: fileID, + line: line + ) + defer { span.end() } + do { + return try await ServiceContext.$current.withValue(span.context) { + try await operation(span) + } + } catch { + span.recordError(error) + throw error // rethrow + } + } + #endif + + @_disfavoredOverload + @available(*, deprecated, message: "Prefer #isolation version of this API") public func withAnySpan( _ operationName: String, context: @autoclosure () -> ServiceContext = .current ?? .topLevel, @@ -524,12 +595,41 @@ extension Tracer { /// - context: The `ServiceContext` providing information on where to start the new ``Span``. /// - kind: The ``SpanKind`` of the new ``Span``. /// - instant: the time instant at which the span started + /// - isolation: Defaulted parameter for inheriting isolation of calling actor /// - 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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) + #if swift(>=6.0) + public func withAnySpan( + _ operationName: String, + at instant: @autoclosure () -> some TracerInstant = DefaultTracerClock.now, + context: @autoclosure () -> ServiceContext = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + isolation: (any Actor)? = #isolation, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + @_inheritActorContext @_implicitSelfCapture _ operation: (any Tracing.Span) async throws -> T + ) async rethrows -> T { + try await self.withSpan( + operationName, + context: context(), + ofKind: kind, + at: instant(), + function: function, + file: fileID, + line: line + ) { span in + try await operation(span) + } + } + #endif + + @_disfavoredOverload + @available(*, deprecated, message: "Prefer #isolation version of this API") public func withAnySpan( _ operationName: String, at instant: @autoclosure () -> some TracerInstant = DefaultTracerClock.now, diff --git a/Sources/Tracing/TracerProtocol.swift b/Sources/Tracing/TracerProtocol.swift index 19d8679..d1bfa39 100644 --- a/Sources/Tracing/TracerProtocol.swift +++ b/Sources/Tracing/TracerProtocol.swift @@ -235,12 +235,47 @@ extension Tracer { /// - context: The `ServiceContext` providing information on where to start the new ``Span``. /// - kind: The ``SpanKind`` of the new ``Span``. /// - instant: the time instant at which the span started + /// - isolation: Defaulted parameter for inheriting isolation of calling actor /// - 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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) + #if swift(>=6.0) + public func withSpan( + _ operationName: String, + context: @autoclosure () -> ServiceContext = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + isolation: (any Actor)? = #isolation, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + @_inheritActorContext @_implicitSelfCapture _ operation: (Self.Span) async throws -> T + ) async rethrows -> T { + let span = self.startSpan( + operationName, + context: context(), + ofKind: kind, + at: DefaultTracerClock.now, + function: function, + file: fileID, + line: line + ) + defer { span.end() } + do { + return try await ServiceContext.$current.withValue(span.context) { + try await operation(span) + } + } catch { + span.recordError(error) + throw error // rethrow + } + } + #endif + + @_disfavoredOverload + @available(*, deprecated, message: "Prefer #isolation version of this API") public func withSpan( _ operationName: String, context: @autoclosure () -> ServiceContext = .current ?? .topLevel, @@ -287,12 +322,48 @@ extension Tracer { /// - context: The `ServiceContext` providing information on where to start the new ``Span``. /// - kind: The ``SpanKind`` of the new ``Span``. /// - instant: the time instant at which the span started + /// - isolation: Defaulted parameter for inheriting isolation of calling actor /// - 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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) + #if swift(>=6.0) + public func withSpan( + _ operationName: String, + context: @autoclosure () -> ServiceContext = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at instant: @autoclosure () -> some TracerInstant = DefaultTracerClock.now, + isolation: (any Actor)? = #isolation, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + @_inheritActorContext @_implicitSelfCapture _ operation: (Self.Span) async throws -> T + ) async rethrows -> T { + let span = self.startSpan( + operationName, + context: context(), + ofKind: kind, + at: instant(), + function: function, + file: fileID, + line: line + ) + defer { span.end() } + do { + return try await ServiceContext.$current.withValue(span.context) { + try await operation(span) + } + } catch { + span.recordError(error) + throw error // rethrow + } + } + #endif + + @_disfavoredOverload + @available(*, deprecated, message: "Prefer #isolation version of this API") public func withSpan( _ operationName: String, context: @autoclosure () -> ServiceContext = .current ?? .topLevel, diff --git a/Tests/TracingTests/ActorTracingTests.swift b/Tests/TracingTests/ActorTracingTests.swift index 1e88f86..87bd4ce 100644 --- a/Tests/TracingTests/ActorTracingTests.swift +++ b/Tests/TracingTests/ActorTracingTests.swift @@ -22,6 +22,8 @@ final class ActorTracingTests: XCTestCase { super.tearDown() InstrumentationSystem.bootstrapInternal(nil) } + + func test() {} } func work() async {}