From 79ccc2f75ff87b0144a53fa337806daff4a066a9 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Fri, 24 Feb 2023 20:49:47 +0900 Subject: [PATCH 1/2] Incomplete idea how to solve the Clock trouble --- .../InstrumentationSystem.swift | 2 + .../InstrumentationSystem+Tracing.swift | 4 +- Sources/Tracing/NoOpTracer.swift | 7 ++- Sources/Tracing/Span.swift | 5 +- Sources/Tracing/Tracer.swift | 9 +++- Sources/Tracing/TracingClock.swift | 49 +++++++++++++++++++ .../InstrumentationSystemTests.swift | 2 + 7 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 Sources/Tracing/TracingClock.swift diff --git a/Sources/Instrumentation/InstrumentationSystem.swift b/Sources/Instrumentation/InstrumentationSystem.swift index 9c512a87..ae226516 100644 --- a/Sources/Instrumentation/InstrumentationSystem.swift +++ b/Sources/Instrumentation/InstrumentationSystem.swift @@ -22,6 +22,7 @@ import InstrumentationBaggage /// /// # Access the Instrument /// ``instrument``: Returns whatever you passed to ``bootstrap(_:)`` as an ``Instrument``. +@available(macOS 13.0, iOS 15.0, *) public enum InstrumentationSystem { private static let lock = ReadWriteLock() private static var _instrument: Instrument = NoOpInstrument() @@ -61,6 +62,7 @@ public enum InstrumentationSystem { } } +@available(macOS 13.0, iOS 15.0, *) extension InstrumentationSystem { /// :nodoc: INTERNAL API: Do Not Use public static func _findInstrument(where predicate: (Instrument) -> Bool) -> Instrument? { diff --git a/Sources/Tracing/InstrumentationSystem+Tracing.swift b/Sources/Tracing/InstrumentationSystem+Tracing.swift index 1be4949c..ca9b8199 100644 --- a/Sources/Tracing/InstrumentationSystem+Tracing.swift +++ b/Sources/Tracing/InstrumentationSystem+Tracing.swift @@ -21,7 +21,7 @@ extension InstrumentationSystem { /// tracing instrument as passed to the multiplex instrument. If none is found, a ``NoOpTracer`` is returned. /// /// - Returns: A ``Tracer`` if the system was bootstrapped with one, and ``NoOpTracer`` otherwise. - public static var tracer: Tracer { - (self._findInstrument(where: { $0 is Tracer }) as? Tracer) ?? NoOpTracer() + public static var tracer: any Tracer { + (self._findInstrument(where: { $0 is Tracer }) as? (any Tracer)) ?? NoOpTracer() } } diff --git a/Sources/Tracing/NoOpTracer.swift b/Sources/Tracing/NoOpTracer.swift index 97bfc35e..692f4f8e 100644 --- a/Sources/Tracing/NoOpTracer.swift +++ b/Sources/Tracing/NoOpTracer.swift @@ -17,7 +17,10 @@ import Dispatch @_exported import InstrumentationBaggage /// No operation ``Tracer``, used when no tracing is required. +@available(macOS 13.0, iOS 15.0, *) public struct NoOpTracer: Tracer { + public typealias Span = NoOpSpan + public init() {} public func startSpan( @@ -46,7 +49,9 @@ public struct NoOpTracer: Tracer { // no-op } - public final class NoOpSpan: Span { + @available(macOS 13.0, iOS 15.0, *) + public final class NoOpSpan: SpanProtocol { + public typealias Clock = TracingClock public let baggage: Baggage public let isRecording = false diff --git a/Sources/Tracing/Span.swift b/Sources/Tracing/Span.swift index ad15b2c3..253940a8 100644 --- a/Sources/Tracing/Span.swift +++ b/Sources/Tracing/Span.swift @@ -26,7 +26,10 @@ import struct Dispatch.DispatchWallTime /// 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, _SwiftTracingSendableSpan { +@available(macOS 13.0, iOS 15.0, *) +public protocol SpanProtocol: AnyObject, _SwiftTracingSendableSpan { + associatedtype Clock: _Concurrency.Clock where Clock.Duration == Swift.Duration + /// The read-only `Baggage` of this `Span`, set when starting this `Span`. var baggage: Baggage { get } diff --git a/Sources/Tracing/Tracer.swift b/Sources/Tracing/Tracer.swift index e0b7eb2f..008e0b1f 100644 --- a/Sources/Tracing/Tracer.swift +++ b/Sources/Tracing/Tracer.swift @@ -18,7 +18,10 @@ import Dispatch /// An `Instrument` with added functionality for distributed tracing. It uses the span-based tracing model and is /// based on the OpenTracing/OpenTelemetry spec. +@available(macOS 13.0, iOS 15.0, *) public protocol Tracer: Instrument { + associatedtype Span: SpanProtocol + /// Start a new ``Span`` with the given `Baggage` at a given time. /// /// - Note: Prefer to use `withSpan` to start a span as it automatically takes care of ending the span, @@ -41,7 +44,7 @@ public protocol Tracer: Instrument { function: String, file fileID: String, line: UInt - ) -> Span + ) -> Self.Span /// Export all ended spans to the configured backend that have not yet been exported. /// @@ -52,6 +55,7 @@ public protocol Tracer: Instrument { func forceFlush() } +@available(macOS 13.0, iOS 15.0, *) extension Tracer { #if swift(>=5.3.0) /// Start a new ``Span`` with the given `Baggage` starting "now". @@ -115,6 +119,7 @@ extension Tracer { // ==== ---------------------------------------------------------------------------------------------------------------- // MARK: Starting spans: `withSpan` +@available(macOS 13.0, iOS 15.0, *) extension Tracer { #if swift(>=5.3.0) /// Execute a specific task within a newly created ``Span``. @@ -205,7 +210,7 @@ extension Tracer { // MARK: Starting spans: Task-local Baggage propagation #if swift(>=5.5) && canImport(_Concurrency) -@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +@available(macOS 13, iOS 15.0, tvOS 13.0, watchOS 6.0, *) extension Tracer { /// Execute the given operation within a newly created ``Span``, /// started as a child of the currently stored task local `Baggage.current` or as a root span if `nil`. diff --git a/Sources/Tracing/TracingClock.swift b/Sources/Tracing/TracingClock.swift new file mode 100644 index 00000000..4e0838a1 --- /dev/null +++ b/Sources/Tracing/TracingClock.swift @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Distributed Tracing open source project +// +// Copyright (c) 2020-2022 Apple Inc. and the Swift Distributed Tracing project +// authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +@available(macOS 13.0, iOS 15.0, *) +public struct TracingClock: _Concurrency.Clock { + public typealias Duration = Swift.Duration + public struct Instant: InstantProtocol { + public typealias Duration = TracingClock.Duration + public var raw: UInt64 + + public func advanced(by duration: TracingClock.Duration) -> TracingClock.Instant { + var copy = self + // FIXME: implement this... + return copy + } + + public func duration(to other: TracingClock.Instant) -> TracingClock.Duration { + return .milliseconds(self.raw - other.raw) + } + + + public static func <(lhs: TracingClock.Instant, rhs: TracingClock.Instant) -> Bool { + lhs.raw < rhs.raw + } + } + + public var now: Instant { + .init(raw: 0) // TODO: implement "now" + } + public var minimumResolution: Duration { + .milliseconds(1) + } + + public func sleep(until deadline: Instant, tolerance: Duration?) async throws { + fatalError("Not implemented for TracingClock") + } +} + diff --git a/Tests/InstrumentationTests/InstrumentationSystemTests.swift b/Tests/InstrumentationTests/InstrumentationSystemTests.swift index 87a7be5c..8e2a3ff3 100644 --- a/Tests/InstrumentationTests/InstrumentationSystemTests.swift +++ b/Tests/InstrumentationTests/InstrumentationSystemTests.swift @@ -16,12 +16,14 @@ import InstrumentationBaggage import XCTest +@available(macOS 13.0, iOS 15.0, *) extension InstrumentationSystem { public static func _instrument(of instrumentType: I.Type) -> I? where I: Instrument { self._findInstrument(where: { $0 is I }) as? I } } +@available(macOS 13.0, iOS 15.0, *) final class InstrumentationSystemTests: XCTestCase { override class func tearDown() { super.tearDown() From ff8b6b2df134205a675f17ee1f94b5ea91d8f9a9 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Fri, 24 Feb 2023 20:51:24 +0900 Subject: [PATCH 2/2] show how we can use the clock --- Sources/Tracing/Span.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Tracing/Span.swift b/Sources/Tracing/Span.swift index 253940a8..229aacfd 100644 --- a/Sources/Tracing/Span.swift +++ b/Sources/Tracing/Span.swift @@ -70,7 +70,7 @@ public protocol SpanProtocol: AnyObject, _SwiftTracingSendableSpan { /// - Parameter time: The `DispatchWallTime` at which the span ended. /// /// - SeeAlso: `Span.end()` which automatically uses the "current" time. - func end(at time: DispatchWallTime) + func end(at time: Clock.Instant) } extension Span {