Skip to content

Incomplete idea how to solve the Clock trouble #91

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

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 2 additions & 0 deletions Sources/Instrumentation/InstrumentationSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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? {
Expand Down
4 changes: 2 additions & 2 deletions Sources/Tracing/InstrumentationSystem+Tracing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
7 changes: 6 additions & 1 deletion Sources/Tracing/NoOpTracer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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

Expand Down
7 changes: 5 additions & 2 deletions Sources/Tracing/Span.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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<Clock>: AnyObject, _SwiftTracingSendableSpan {
associatedtype Clock: _Concurrency.Clock where Clock.Duration == Swift.Duration
Copy link
Member Author

Choose a reason for hiding this comment

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

"The change"™


/// The read-only `Baggage` of this `Span`, set when starting this `Span`.
var baggage: Baggage { get }

Expand Down Expand Up @@ -67,7 +70,7 @@ public protocol Span: 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)
Copy link
Member Author

Choose a reason for hiding this comment

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

And this way we got rid of the Dispatch types in API - which would have stayed with us "forever"

}

extension Span {
Expand Down
9 changes: 7 additions & 2 deletions Sources/Tracing/Tracer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -41,7 +44,7 @@ public protocol Tracer: Instrument {
function: String,
file fileID: String,
line: UInt
) -> Span
) -> Self.Span
Copy link
Member Author

Choose a reason for hiding this comment

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

We'll be returning concrete spans then, as requested in another issue


/// Export all ended spans to the configured backend that have not yet been exported.
///
Expand All @@ -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".
Expand Down Expand Up @@ -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``.
Expand Down Expand Up @@ -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`.
Expand Down
49 changes: 49 additions & 0 deletions Sources/Tracing/TracingClock.swift
Original file line number Diff line number Diff line change
@@ -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 {
Copy link
Member Author

Choose a reason for hiding this comment

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

We have to implement a TracingClock that gives us unit timestamps for "now", since there is no clock implementation in Swift which does this.

If we get one, we'd deprecate this type immediately

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")
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Potentially, we could not implement sleeping on it at all tbh

}

2 changes: 2 additions & 0 deletions Tests/InstrumentationTests/InstrumentationSystemTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
import InstrumentationBaggage
import XCTest

@available(macOS 13.0, iOS 15.0, *)
extension InstrumentationSystem {
public static func _instrument<I>(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()
Expand Down