From 43795ed0124f2ce685da4609b3fd374ed04ac59b Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 23 Mar 2023 22:04:00 +0900 Subject: [PATCH 1/9] Implement TracerClock and abstract away "now" **Motivation:** we do not want to be bound to DispatchWallTime, but we cannot require Clock. We need to introduce a shim type TracerClockProtocol that in the future we'll be able to conform a "good Swift clock" to. This removes any dependencies on dispatch and makes the Time source swappable. We also implement our own unix timestamp clock. --- Package.swift | 5 + .../include/tracing_time_support.h | 16 + .../tracing_time_support.c | 46 +++ Sources/Tracing/NoOpTracer.swift | 23 +- Sources/Tracing/SpanProtocol.swift | 4 +- Sources/Tracing/Tracer.swift | 127 ++++++- Sources/Tracing/TracerProtocol+Legacy.swift | 195 ++++++++++- Sources/Tracing/TracerProtocol.swift | 57 +++- Sources/Tracing/TracingTime.swift | 238 +++++++++++++ .../SpanAttributesDSLBenchmark.swift | 312 +++++++++--------- Sources/_TracingBenchmarks/main.swift | 74 ++--- .../DynamicTracepointTracerTests.swift | 54 +-- Tests/TracingTests/SpanTests.swift | 8 +- Tests/TracingTests/TestTracer.swift | 22 +- Tests/TracingTests/TracedLockTests.swift | 24 +- Tests/TracingTests/TracerTests.swift | 20 +- 16 files changed, 933 insertions(+), 292 deletions(-) create mode 100644 Sources/CTracingTimeSupport/include/tracing_time_support.h create mode 100644 Sources/CTracingTimeSupport/tracing_time_support.c create mode 100644 Sources/Tracing/TracingTime.swift diff --git a/Package.swift b/Package.swift index 435c511e..426dba0d 100644 --- a/Package.swift +++ b/Package.swift @@ -41,8 +41,13 @@ let package = Package( name: "Tracing", dependencies: [ .target(name: "Instrumentation"), + .target(name: "CTracingTimeSupport"), ] ), + .target( + name: "CTracingTimeSupport", + dependencies: [] + ), .testTarget( name: "TracingTests", dependencies: [ diff --git a/Sources/CTracingTimeSupport/include/tracing_time_support.h b/Sources/CTracingTimeSupport/include/tracing_time_support.h new file mode 100644 index 00000000..430c9b5d --- /dev/null +++ b/Sources/CTracingTimeSupport/include/tracing_time_support.h @@ -0,0 +1,16 @@ +// +// Created by Konrad 'ktoso' Malawski on 3/23/23. +// + +#ifndef SWIFT_DISTRIBUTED_TRACING_TRACING_TIME_SUPPORT_H +#define SWIFT_DISTRIBUTED_TRACING_TRACING_TIME_SUPPORT_H + + +typedef double SDTTimeInterval; +typedef SDTTimeInterval SDTAbsoluteTime; +/* absolute time is the time interval since the reference date */ +/* the reference date (epoch) is 00:00:00 1 January 2001. */ + +SDTAbsoluteTime SDTAbsoluteTimeGetCurrent(); + +#endif //SWIFT_DISTRIBUTED_TRACING_TRACING_TIME_SUPPORT_H diff --git a/Sources/CTracingTimeSupport/tracing_time_support.c b/Sources/CTracingTimeSupport/tracing_time_support.c new file mode 100644 index 00000000..3dd33a59 --- /dev/null +++ b/Sources/CTracingTimeSupport/tracing_time_support.c @@ -0,0 +1,46 @@ +// +// Created by Konrad 'ktoso' Malawski on 3/23/23. +// + +#include "include/tracing_time_support.h" + +#if __HAS_DISPATCH__ +#include +#else + #ifndef NSEC_PER_SEC + #define NSEC_PER_SEC 1000000000UL + #endif +#endif + +//#if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI +#include +//#endif + +const SDTTimeInterval kCFAbsoluteTimeIntervalSince1970 = 978307200.0L; +const SDTTimeInterval kCFAbsoluteTimeIntervalSince1904 = 3061152000.0L; + + +//#if TARGET_OS_WIN32 +//CFAbsoluteTime CFAbsoluteTimeGetCurrent(void) { +// SYSTEMTIME stTime; +// FILETIME ftTime; +// +// GetSystemTime(&stTime); +// SystemTimeToFileTime(&stTime, &ftTime); +// +// // 100ns intervals since NT Epoch +// uint64_t result = ((uint64_t)ftTime.dwHighDateTime << 32) +// | ((uint64_t)ftTime.dwLowDateTime << 0); +// return result * 1.0e-7 - kCFAbsoluteTimeIntervalSince1601; +//} +//#else +SDTAbsoluteTime SDTAbsoluteTimeGetCurrent() { + SDTAbsoluteTime ret; + struct timeval tv; + gettimeofday(&tv, NULL); + ret = (SDTTimeInterval)tv.tv_sec - kCFAbsoluteTimeIntervalSince1970; + ret += (1.0E-6 * (SDTTimeInterval)tv.tv_usec); + return ret; +} + +//#endif \ No newline at end of file diff --git a/Sources/Tracing/NoOpTracer.swift b/Sources/Tracing/NoOpTracer.swift index 2c930168..4d7e8dde 100644 --- a/Sources/Tracing/NoOpTracer.swift +++ b/Sources/Tracing/NoOpTracer.swift @@ -17,18 +17,20 @@ import Dispatch @_exported import InstrumentationBaggage /// Tracer that ignores all operations, used when no tracing is required. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage public struct NoOpTracer: LegacyTracerProtocol { public typealias TracerSpan = NoOpSpan public init() {} - public func startAnySpan(_ operationName: String, - baggage: @autoclosure () -> Baggage, - ofKind kind: SpanKind, - at time: DispatchWallTime, - function: String, - file fileID: String, - line: UInt) -> any Span + public func startAnySpan(_ operationName: String, + baggage: @autoclosure () -> Baggage, + ofKind kind: SpanKind, + at time: Clock.Instant, + clock: Clock, + function: String, + file fileID: String, + line: UInt) -> any Span { NoOpSpan(baggage: baggage()) } @@ -83,7 +85,7 @@ public struct NoOpTracer: LegacyTracerProtocol { } } - public func end(at time: DispatchWallTime) { + public func end(at time: Clock.Instant, clock: Clock) { // ignore } } @@ -91,11 +93,12 @@ public struct NoOpTracer: LegacyTracerProtocol { #if swift(>=5.7.0) extension NoOpTracer: TracerProtocol { - public func startSpan( + public func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: DispatchWallTime, + at time: Clock.Instant, + clock: Clock, function: String, file fileID: String, line: UInt diff --git a/Sources/Tracing/SpanProtocol.swift b/Sources/Tracing/SpanProtocol.swift index 30eef12d..8be5e9bc 100644 --- a/Sources/Tracing/SpanProtocol.swift +++ b/Sources/Tracing/SpanProtocol.swift @@ -101,7 +101,7 @@ public protocol Span: _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, clock: Clock) } extension Span { @@ -120,7 +120,7 @@ extension Span { /// - SeeAlso: ``end(at:)`` which allows passing in a specific time, e.g. if the operation was ended and recorded somewhere and we need to post-factum record it. /// Generally though prefer using the ``end()`` version of this API in user code and structure your system such that it can be called in the right place and time. public func end() { - self.end(at: .now()) + self.end(at: TracerClock.now, clock: TracerClock()) } /// Adds a ``SpanLink`` between this `Span` and the given `Span`. diff --git a/Sources/Tracing/Tracer.swift b/Sources/Tracing/Tracer.swift index 2138a96c..4b1709d3 100644 --- a/Sources/Tracing/Tracer.swift +++ b/Sources/Tracing/Tracer.swift @@ -50,11 +50,12 @@ extension Tracer { /// - 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. + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage static func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: TracerClock.Instant = TracerClock.now, function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -64,6 +65,68 @@ extension Tracer { #if swift(>=5.7.0) InstrumentationSystem.tracer.startSpan( operationName, + at: time, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) + #else + InstrumentationSystem.legacyTracer.startAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: time, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) + #endif + } + + /// Start a new ``Span`` using the global bootstrapped tracer reimplementation. + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Note: Prefer ``withSpan(_:baggage:ofKind:at:function:file:line:operation:)`` to start + /// a span as it automatically takes care of ending the span, and recording errors when thrown. + /// Use `startSpan` iff you need to pass the span manually to a different + /// location in your source code to end it. + /// + /// - Warning: You must `end()` the span when it the measured operation has completed explicitly, + /// otherwise the span object will potentially never be released nor reported. + /// + /// - Parameters: + /// - 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 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. + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage + static func startSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line + ) -> any Span { + // Effectively these end up calling the same method, however + // we try to not use the deprecated methods ourselves anyway + #if swift(>=5.7.0) + InstrumentationSystem.tracer.startSpan( + operationName, + at: time, + clock: clock, function: function, file: fileID, line: line @@ -104,6 +167,7 @@ extension Tracer { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage public static func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, @@ -160,23 +224,74 @@ extension Tracer { /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) #if swift(>=5.7.0) - @_unsafeInheritExecutor + public static func withSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at time: TracerClock.Instant = TracerClock.now, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T + ) async rethrows -> T { + try await InstrumentationSystem.legacyTracer.withAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: time, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) { anySpan in + try await operation(anySpan) + } + } + #else // TODO: remove this if/else when we require 5.7 @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) public static func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: TracerClock.Instant = .now, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T + ) async rethrows -> T { + try await InstrumentationSystem.legacyTracer.withAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: time, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) { anySpan in + try await operation(anySpan) + } + } + #endif + + #if swift(>=5.7.0) + public static func withSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any Span) async throws -> T + @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T ) async rethrows -> T { try await InstrumentationSystem.legacyTracer.withAnySpan( operationName, baggage: baggage(), ofKind: kind, at: time, + clock: clock, function: function, file: fileID, line: line @@ -184,7 +299,7 @@ extension Tracer { try await operation(anySpan) } } - #else // TODO: remove this if/else when we require 5.7; it is only here to add @_unsafeInheritExecutor + #else // TODO: remove this if/else when we require 5.7 @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) public static func withSpan( _ operationName: String, @@ -194,7 +309,7 @@ extension Tracer { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any Span) async throws -> T + @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T ) async rethrows -> T { try await InstrumentationSystem.legacyTracer.withAnySpan( operationName, diff --git a/Sources/Tracing/TracerProtocol+Legacy.swift b/Sources/Tracing/TracerProtocol+Legacy.swift index 07e3da69..74f0f527 100644 --- a/Sources/Tracing/TracerProtocol+Legacy.swift +++ b/Sources/Tracing/TracerProtocol+Legacy.swift @@ -47,11 +47,12 @@ public protocol LegacyTracerProtocol: InstrumentProtocol { /// - 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. - func startAnySpan( + func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: DispatchWallTime, + at time: Clock.Instant, + clock: Clock, function: String, file fileID: String, line: UInt @@ -104,7 +105,7 @@ extension LegacyTracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: TracerClock.Instant = TracerClock.now, function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -113,7 +114,30 @@ extension LegacyTracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, + at: TracerClock.now, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) + } + + public func startAnySpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line + ) -> any Span { + self.startAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: clock.now, + clock: clock, function: function, file: fileID, line: line @@ -157,13 +181,54 @@ extension LegacyTracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: TracerClock.Instant = TracerClock.now, function: String = #function, file fileID: String = #fileID, line: UInt = #line, _ operation: (any Span) throws -> T ) rethrows -> T { - let span = self.startAnySpan(operationName, baggage: baggage(), ofKind: kind, at: time, function: function, file: fileID, line: line) + let span = self.startAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: time, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) + defer { span.end() } + do { + return try Baggage.$current.withValue(span.baggage) { + try operation(span) + } + } catch { + span.recordError(error) + throw error // rethrow + } + } + + public func withAnySpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Span) throws -> T + ) rethrows -> T { + let span = self.startAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: time, + clock: clock, + function: function, + file: fileID, + line: line + ) defer { span.end() } do { return try Baggage.$current.withValue(span.baggage) { @@ -212,13 +277,54 @@ extension LegacyTracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: TracerClock.Instant = TracerClock.now, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Span) async throws -> T + ) async rethrows -> T { + let span = self.startAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: time, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) + defer { span.end() } + do { + return try await Baggage.$current.withValue(span.baggage) { + try await operation(span) + } + } catch { + span.recordError(error) + throw error // rethrow + } + } + + public func withAnySpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, _ operation: (any Span) async throws -> T ) async rethrows -> T { - let span = self.startAnySpan(operationName, baggage: baggage(), ofKind: kind, at: time, function: function, file: fileID, line: line) + let span = self.startAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: time, + clock: clock, + function: function, + file: fileID, + line: line + ) defer { span.end() } do { return try await Baggage.$current.withValue(span.baggage) { @@ -234,7 +340,7 @@ extension LegacyTracerProtocol { #if swift(>=5.7.0) // Provide compatibility shims of the `...AnySpan` APIs to the 5.7 requiring `TracerProtocol`. -@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) extension TracerProtocol { /// Start a new span returning an existential ``Span`` reference. /// @@ -269,7 +375,56 @@ extension TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line + ) -> any Span { + self.startAnySpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: TracerClock.now, + function: function, + file: fileID, + line: line + ) + } + + /// Start a new span returning an existential ``Span`` reference. + /// + /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` + /// is recommended instead. + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Note: Legacy API, prefer using ``startSpan(_:baggage:ofKind:at: + /// + /// - Note: Prefer ``withSpan(_:baggage:ofKind:at:function:file:line:operation:)`` to start + /// a span as it automatically takes care of ending the span, and recording errors when thrown. + /// Use `startSpan` iff you need to pass the span manually to a different + /// location in your source code to end it. + /// + /// - Warning: You must `end()` the span when it the measured operation has completed explicitly, + /// otherwise the span object will potentially never be released nor reported. + /// + /// - Parameters: + /// - 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 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. + public func startAnySpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -279,6 +434,7 @@ extension TracerProtocol { baggage: baggage(), ofKind: kind, at: time, + clock: clock, function: function, file: fileID, line: line @@ -318,11 +474,12 @@ extension TracerProtocol { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) - public func withAnySpan( + public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -333,6 +490,7 @@ extension TracerProtocol { baggage: baggage(), ofKind: kind, at: time, + clock: clock, function: function, file: fileID, line: line @@ -375,22 +533,23 @@ extension TracerProtocol { /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) #if swift(>=5.7.0) - @_unsafeInheritExecutor - public func withAnySpan( + public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any Span) async throws -> T + @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T ) async rethrows -> T { try await self.withSpan( operationName, baggage: baggage(), ofKind: kind, at: time, + clock: clock, function: function, file: fileID, line: line @@ -404,11 +563,11 @@ extension TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: some TracerInstantProtocol, function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any Span) async throws -> T + @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T ) async rethrows -> T { try await self.withSpan( operationName, diff --git a/Sources/Tracing/TracerProtocol.swift b/Sources/Tracing/TracerProtocol.swift index 9017334d..4b53889f 100644 --- a/Sources/Tracing/TracerProtocol.swift +++ b/Sources/Tracing/TracerProtocol.swift @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -import Dispatch @_exported import Instrumentation @_exported import InstrumentationBaggage @@ -52,11 +51,12 @@ public protocol TracerProtocol: LegacyTracerProtocol { /// - 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. - func startSpan( + func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: DispatchWallTime, + at time: Clock.Instant, + clock: Clock, function: String, file fileID: String, line: UInt @@ -89,11 +89,12 @@ extension TracerProtocol { /// - 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. - public func startSpan( + public func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -103,6 +104,7 @@ extension TracerProtocol { baggage: baggage(), ofKind: kind, at: time, + clock: clock, function: function, file: fileID, line: line @@ -113,7 +115,6 @@ extension TracerProtocol { // ==== ---------------------------------------------------------------------------------------------------------------- // MARK: Starting spans: `withSpan` -@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage extension TracerProtocol { /// Start a new ``Span`` and automatically end when the `operation` completes, /// including recording the `error` in case the operation throws. @@ -138,11 +139,43 @@ extension TracerProtocol { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) + public func withSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (TracerSpan) throws -> T + ) rethrows -> T { + let span = self.startSpan( + operationName, + baggage: baggage(), + ofKind: kind, + at: time, + clock: clock, + function: function, + file: fileID, + line: line + ) + defer { span.end() } + do { + return try Baggage.$current.withValue(span.baggage) { + try operation(span) + } + } catch { + span.recordError(error) + throw error // rethrow + } + } + public func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: TracerClock.Instant = TracerClock.now, function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -153,6 +186,7 @@ extension TracerProtocol { baggage: baggage(), ofKind: kind, at: time, + clock: TracerClock(), function: function, file: fileID, line: line @@ -191,22 +225,23 @@ extension TracerProtocol { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) - @_unsafeInheritExecutor - public func withSpan( + public func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (TracerSpan) async throws -> T + @_inheritActorContext @_implicitSelfCapture _ operation: (TracerSpan) async throws -> T ) async rethrows -> T { let span = self.startSpan( operationName, baggage: baggage(), ofKind: kind, at: time, + clock: clock, function: function, file: fileID, line: line diff --git a/Sources/Tracing/TracingTime.swift b/Sources/Tracing/TracingTime.swift new file mode 100644 index 00000000..60722234 --- /dev/null +++ b/Sources/Tracing/TracingTime.swift @@ -0,0 +1,238 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import CTracingTimeSupport +import Dispatch +@_exported import Instrumentation +@_exported import InstrumentationBaggage + +// FIXME: mirrors DurationProtocol +public protocol SwiftDistributedTracingDurationProtocol: Comparable, AdditiveArithmetic, Sendable { + static func / (_ lhs: Self, _ rhs: Int) -> Self + static func /= (_ lhs: inout Self, _ rhs: Int) + static func * (_ lhs: Self, _ rhs: Int) -> Self + static func *= (_ lhs: inout Self, _ rhs: Int) + + static func / (_ lhs: Self, _ rhs: Self) -> Double +} + +extension SwiftDistributedTracingDurationProtocol { + public static func /= (_ lhs: inout Self, _ rhs: Int) { + lhs = lhs / rhs + } +} + +// #if swift(>=5.7.0) +// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) +// public protocol SwiftDistributedTracingInstantProtocol: InstantProtocol {} +// #else +public protocol SwiftDistributedTracingInstantProtocol: Comparable, Hashable, Sendable { + // associatedtype Duration: SwiftDistributedTracingDurationProtocol +} + +// #endif + +// #if swift(>=5.7.0) +// public protocol SwiftDistributedTracingClock: Clock {} +// #else +public protocol SwiftDistributedTracingClock: Sendable {} +// #endif + +public protocol TracerInstantProtocol: SwiftDistributedTracingInstantProtocol { + /// Representation of this instant as the number of milliseconds since UNIX Epoch (January 1st 1970) + @inlinable + var millisSinceEpoch: Int64 { get } +} + +public protocol TracerClockProtocol: SwiftDistributedTracingClock { + // associatedtype Duration where Self.Duration == Self.Instant.Duration + associatedtype Instant: TracerInstantProtocol + + static var now: Self.Instant { get } + var now: Self.Instant { get } +} + +extension TracerClock { + // public typealias Duration = Swift.Duration +} + +public struct TracerClock: TracerClockProtocol { + // LIKE FOUNDATION + internal typealias TimeInterval = Double + + public init() { + // empty + } + + public struct Instant: TracerInstantProtocol { +// #if swift(>=5.7.0) +// public typealias Duration = Swift.Duration +// #endif + + public var millisSinceEpoch: Int64 + + internal init(millisSinceEpoch: Int64) { + self.millisSinceEpoch = millisSinceEpoch + } + +// public func advanced(by duration: Self.Duration) -> Self { +// var copy = self +// copy.millisSinceEpoch += duration.milliseconds +// return copy +// } +// +// public func duration(to other: Self) -> Self.Duration { +// Duration.milliseconds(self.millisSinceEpoch - other.millisSinceEpoch) +// } + + public static func < (lhs: Instant, rhs: Instant) -> Bool { + lhs.millisSinceEpoch < rhs.millisSinceEpoch + } + + public static func == (lhs: Instant, rhs: Instant) -> Bool { + lhs.millisSinceEpoch == rhs.millisSinceEpoch + } + + public func hash(into hasher: inout Hasher) { + self.millisSinceEpoch.hash(into: &hasher) + } + } + + public static var now: Self.Instant { + TracerClock().now + } + + /// The number of seconds from 1 January 1970 to the reference date, 1 January 2001. + internal static let timeIntervalBetween1970AndReferenceDate: TimeInterval = 978_307_200.0 + + /// The interval between 00:00:00 UTC on 1 January 2001 and the current date and time. + internal static var timeIntervalSinceReferenceDate: TimeInterval { + CTracingTimeSupport.SDTAbsoluteTimeGetCurrent() + } + + public var now: Self.Instant { + let sinceReference = TracerClock.timeIntervalSinceReferenceDate + let between1970AndReference = TracerClock.timeIntervalBetween1970AndReferenceDate + let nowDouble = sinceReference + between1970AndReference + let nowMillis = Int64((nowDouble * 1000).rounded()) + + return Instant(millisSinceEpoch: nowMillis) + } + + // #if swift(>=5.7.0) + // public var minimumResolution: Self.Duration { +// .milliseconds(1) + // } + // #endif +} + +// #if swift(>=5.7.0) +// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) +// extension TracerClock: Clock { +// +// @available(*, deprecated, message: "TracerClock is not able to sleep()") +// public func sleep(until deadline: Self.Instant, tolerance: Instant.Duration?) async throws { +// fatalError("\(TracerClock.self) does not implement sleep() capabilities!") +// } +// +// } +// #endif + +extension DispatchWallTime { + internal init(millisSinceEpoch: Int64) { + let nanoSinceEpoch = UInt64(millisSinceEpoch) * 1_000_000 + let seconds = UInt64(nanoSinceEpoch / 1_000_000_000) + let nanoseconds = nanoSinceEpoch - (seconds * 1_000_000_000) + self.init(timespec: timespec(tv_sec: Int(seconds), tv_nsec: Int(nanoseconds))) + } + + internal var millisSinceEpoch: Int64 { + Int64(bitPattern: self.rawValue) / -1_000_000 + } +} + +#if swift(>=5.7.0) +@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) +extension Duration { + typealias Value = Int64 + + var nanoseconds: Value { + let (seconds, attoseconds) = self.components + let sNanos = seconds * Value(1_000_000_000) + let asNanos = attoseconds / Value(1_000_000_000) + let (totalNanos, overflow) = sNanos.addingReportingOverflow(asNanos) + return overflow ? .max : totalNanos + } + + /// The microseconds representation of the `TimeAmount`. + var microseconds: Value { + self.nanoseconds / TimeUnit.microseconds.rawValue + } + + /// The milliseconds representation of the `TimeAmount`. + var milliseconds: Value { + self.nanoseconds / TimeUnit.milliseconds.rawValue + } + + /// The seconds representation of the `TimeAmount`. + var seconds: Value { + self.nanoseconds / TimeUnit.seconds.rawValue + } + + var isEffectivelyInfinite: Bool { + self.nanoseconds == .max + } +} + +@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) +extension Duration { + private func chooseUnit(_ ns: Value) -> TimeUnit { + if ns / TimeUnit.seconds.rawValue > 0 { + return TimeUnit.seconds + } else if ns / TimeUnit.milliseconds.rawValue > 0 { + return TimeUnit.milliseconds + } else if ns / TimeUnit.microseconds.rawValue > 0 { + return TimeUnit.microseconds + } else { + return TimeUnit.nanoseconds + } + } + + /// Represents number of nanoseconds within given time unit + enum TimeUnit: Value { + case seconds = 1_000_000_000 + case milliseconds = 1_000_000 + case microseconds = 1000 + case nanoseconds = 1 + + var abbreviated: String { + switch self { + case .nanoseconds: return "ns" + case .microseconds: return "μs" + case .milliseconds: return "ms" + case .seconds: return "s" + } + } + + func duration(_ duration: Int) -> Duration { + switch self { + case .nanoseconds: return .nanoseconds(Value(duration)) + case .microseconds: return .microseconds(Value(duration)) + case .milliseconds: return .milliseconds(Value(duration)) + case .seconds: return .seconds(Value(duration)) + } + } + } +} +#endif diff --git a/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift b/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift index 8281fc58..9b09270f 100644 --- a/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift +++ b/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift @@ -1,156 +1,156 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift Distributed Tracing open source project -// -// Copyright (c) 2020-2021 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 -// -//===----------------------------------------------------------------------===// - -import _TracingBenchmarkTools -import Tracing - -public let SpanAttributesDSLBenchmarks: [BenchmarkInfo] = [ - BenchmarkInfo( - name: "SpanAttributesDSLBenchmarks.000_bench_empty", - runFunction: { _ in try! bench_empty(times: 100) }, - tags: [], - setUpFunction: { setUp() }, - tearDownFunction: tearDown - ), - BenchmarkInfo( - name: "SpanAttributesDSLBenchmarks.001_bench_makeSpan", - runFunction: { _ in try! bench_makeSpan(times: 100) }, - tags: [], - setUpFunction: { setUp() }, - tearDownFunction: tearDown - ), - BenchmarkInfo( - name: "SpanAttributesDSLBenchmarks.002_bench_startSpan_end", - runFunction: { _ in try! bench_makeSpan(times: 100) }, - tags: [], - setUpFunction: { setUp() }, - tearDownFunction: tearDown - ), - - BenchmarkInfo( - name: "SpanAttributesDSLBenchmarks.00_bench_set_String_raw", - runFunction: { _ in try! bench_set_String_raw(times: 100) }, - tags: [], - setUpFunction: { setUp() }, - tearDownFunction: tearDown - ), - BenchmarkInfo( - name: "SpanAttributesDSLBenchmarks.01_bench_set_String_dsl", - runFunction: { _ in try! bench_set_String_dsl(times: 100) }, - tags: [], - setUpFunction: { setUp() }, - tearDownFunction: tearDown - ), - - BenchmarkInfo( - name: "SpanAttributesDSLBenchmarks.02_bench_set_Int_raw", - runFunction: { _ in try! bench_set_String_raw(times: 100) }, - tags: [], - setUpFunction: { setUp() }, - tearDownFunction: tearDown - ), - BenchmarkInfo( - name: "SpanAttributesDSLBenchmarks.03_bench_set_Int_dsl", - runFunction: { _ in try! bench_set_String_dsl(times: 100) }, - tags: [], - setUpFunction: { setUp() }, - tearDownFunction: tearDown - ), -] - -private var span: (any Span)! - -private func setUp() { - span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) -} - -private func tearDown() { - span = nil -} - -// ==== ---------------------------------------------------------------------------------------------------------------- -// MARK: make span - -func bench_empty(times: Int) throws {} - -func bench_makeSpan(times: Int) throws { - for _ in 0 ..< times { - let span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) - _ = span - } -} - -func bench_startSpan_end(times: Int) throws { - for _ in 0 ..< times { - let span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) - span.end() - } -} - -// ==== ---------------------------------------------------------------------------------------------------------------- -// MARK: set String - -func bench_set_String_raw(times: Int) throws { - for _ in 0 ..< times { - span.attributes["http.method"] = "POST" - } -} - -func bench_set_String_dsl(times: Int) throws { - for _ in 0 ..< times { - span.attributes.http.method = "POST" - } -} - -// ==== ---------------------------------------------------------------------------------------------------------------- -// MARK: set Int - -func bench_set_Int_raw(times: Int) throws { - for _ in 0 ..< times { - span.attributes["http.status_code"] = 200 - } -} - -func bench_set_Int_dsl(times: Int) throws { - for _ in 0 ..< times { - span.attributes.http.statusCode = 200 - } -} - -extension SpanAttributes { - var http: HTTPAttributes { - get { - .init(attributes: self) - } - set { - self = newValue.attributes - } - } -} - -@dynamicMemberLookup -struct HTTPAttributes: SpanAttributeNamespace { - var attributes: SpanAttributes - - init(attributes: SpanAttributes) { - self.attributes = attributes - } - - struct NestedSpanAttributes: NestedSpanAttributesProtocol { - init() {} - - var method: Key { "http.method" } - var statusCode: Key { "http.status_code" } - } -} +////===----------------------------------------------------------------------===// +//// +//// This source file is part of the Swift Distributed Tracing open source project +//// +//// Copyright (c) 2020-2021 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 +//// +////===----------------------------------------------------------------------===// +// +// import _TracingBenchmarkTools +// import Tracing +// +// public let SpanAttributesDSLBenchmarks: [BenchmarkInfo] = [ +// BenchmarkInfo( +// name: "SpanAttributesDSLBenchmarks.000_bench_empty", +// runFunction: { _ in try! bench_empty(times: 100) }, +// tags: [], +// setUpFunction: { setUp() }, +// tearDownFunction: tearDown +// ), +// BenchmarkInfo( +// name: "SpanAttributesDSLBenchmarks.001_bench_makeSpan", +// runFunction: { _ in try! bench_makeSpan(times: 100) }, +// tags: [], +// setUpFunction: { setUp() }, +// tearDownFunction: tearDown +// ), +// BenchmarkInfo( +// name: "SpanAttributesDSLBenchmarks.002_bench_startSpan_end", +// runFunction: { _ in try! bench_makeSpan(times: 100) }, +// tags: [], +// setUpFunction: { setUp() }, +// tearDownFunction: tearDown +// ), +// +// BenchmarkInfo( +// name: "SpanAttributesDSLBenchmarks.00_bench_set_String_raw", +// runFunction: { _ in try! bench_set_String_raw(times: 100) }, +// tags: [], +// setUpFunction: { setUp() }, +// tearDownFunction: tearDown +// ), +// BenchmarkInfo( +// name: "SpanAttributesDSLBenchmarks.01_bench_set_String_dsl", +// runFunction: { _ in try! bench_set_String_dsl(times: 100) }, +// tags: [], +// setUpFunction: { setUp() }, +// tearDownFunction: tearDown +// ), +// +// BenchmarkInfo( +// name: "SpanAttributesDSLBenchmarks.02_bench_set_Int_raw", +// runFunction: { _ in try! bench_set_String_raw(times: 100) }, +// tags: [], +// setUpFunction: { setUp() }, +// tearDownFunction: tearDown +// ), +// BenchmarkInfo( +// name: "SpanAttributesDSLBenchmarks.03_bench_set_Int_dsl", +// runFunction: { _ in try! bench_set_String_dsl(times: 100) }, +// tags: [], +// setUpFunction: { setUp() }, +// tearDownFunction: tearDown +// ), +// ] +// +// private var span: (any Span)! +// +// private func setUp() { +// span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) +// } +// +// private func tearDown() { +// span = nil +// } +// +//// ==== ---------------------------------------------------------------------------------------------------------------- +//// MARK: make span +// +// func bench_empty(times: Int) throws {} +// +// func bench_makeSpan(times: Int) throws { +// for _ in 0 ..< times { +// let span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) +// _ = span +// } +// } +// +// func bench_startSpan_end(times: Int) throws { +// for _ in 0 ..< times { +// let span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) +// span.end() +// } +// } +// +//// ==== ---------------------------------------------------------------------------------------------------------------- +//// MARK: set String +// +// func bench_set_String_raw(times: Int) throws { +// for _ in 0 ..< times { +// span.attributes["http.method"] = "POST" +// } +// } +// +// func bench_set_String_dsl(times: Int) throws { +// for _ in 0 ..< times { +// span.attributes.http.method = "POST" +// } +// } +// +//// ==== ---------------------------------------------------------------------------------------------------------------- +//// MARK: set Int +// +// func bench_set_Int_raw(times: Int) throws { +// for _ in 0 ..< times { +// span.attributes["http.status_code"] = 200 +// } +// } +// +// func bench_set_Int_dsl(times: Int) throws { +// for _ in 0 ..< times { +// span.attributes.http.statusCode = 200 +// } +// } +// +// extension SpanAttributes { +// var http: HTTPAttributes { +// get { +// .init(attributes: self) +// } +// set { +// self = newValue.attributes +// } +// } +// } +// +// @dynamicMemberLookup +// struct HTTPAttributes: SpanAttributeNamespace { +// var attributes: SpanAttributes +// +// init(attributes: SpanAttributes) { +// self.attributes = attributes +// } +// +// struct NestedSpanAttributes: NestedSpanAttributesProtocol { +// init() {} +// +// var method: Key { "http.method" } +// var statusCode: Key { "http.status_code" } +// } +// } diff --git a/Sources/_TracingBenchmarks/main.swift b/Sources/_TracingBenchmarks/main.swift index 4ae4b3aa..82c37822 100644 --- a/Sources/_TracingBenchmarks/main.swift +++ b/Sources/_TracingBenchmarks/main.swift @@ -1,42 +1,42 @@ -//===----------------------------------------------------------------------===// +////===----------------------------------------------------------------------===// +//// +//// This source file is part of the Swift Distributed Tracing open source project +//// +//// Copyright (c) 2020-2021 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 +//// +////===----------------------------------------------------------------------===// // -// This source file is part of the Swift Distributed Tracing open source project +// import _TracingBenchmarkTools // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project -// authors -// Licensed under Apache License v2.0 +// assert({ +// print("===========================================================================") +// print("= !! YOU ARE RUNNING BENCHMARKS IN DEBUG MODE !! =") +// print("= When running on the command line, use: `swift run -c release` =") +// print("===========================================================================") +// return true +// }()) // -// See LICENSE.txt for license information +// @inline(__always) +// private func registerBenchmark(_ bench: BenchmarkInfo) { +// registeredBenchmarks.append(bench) +// } // -// SPDX-License-Identifier: Apache-2.0 +// @inline(__always) +// private func registerBenchmark(_ benches: [BenchmarkInfo]) { +// benches.forEach(registerBenchmark) +// } // -//===----------------------------------------------------------------------===// - -import _TracingBenchmarkTools - -assert({ - print("===========================================================================") - print("= !! YOU ARE RUNNING BENCHMARKS IN DEBUG MODE !! =") - print("= When running on the command line, use: `swift run -c release` =") - print("===========================================================================") - return true -}()) - -@inline(__always) -private func registerBenchmark(_ bench: BenchmarkInfo) { - registeredBenchmarks.append(bench) -} - -@inline(__always) -private func registerBenchmark(_ benches: [BenchmarkInfo]) { - benches.forEach(registerBenchmark) -} - -@inline(__always) -private func registerBenchmark(_ name: String, _ function: @escaping (Int) -> Void, _ tags: [BenchmarkCategory]) { - registerBenchmark(BenchmarkInfo(name: name, runFunction: function, tags: tags)) -} - -registerBenchmark(SpanAttributesDSLBenchmarks) - -main() +// @inline(__always) +// private func registerBenchmark(_ name: String, _ function: @escaping (Int) -> Void, _ tags: [BenchmarkCategory]) { +// registerBenchmark(BenchmarkInfo(name: name, runFunction: function, tags: tags)) +// } +// +// registerBenchmark(SpanAttributesDSLBenchmarks) +// +// main() diff --git a/Tests/TracingTests/DynamicTracepointTracerTests.swift b/Tests/TracingTests/DynamicTracepointTracerTests.swift index 1904d63f..65a978e2 100644 --- a/Tests/TracingTests/DynamicTracepointTracerTests.swift +++ b/Tests/TracingTests/DynamicTracepointTracerTests.swift @@ -24,7 +24,6 @@ final class DynamicTracepointTracerTests: XCTestCase { } func test_adhoc_enableBySourceLoc() { - #if swift(>=5.5) let tracer = DynamicTracepointTestTracer() InstrumentationSystem.bootstrapInternal(tracer) @@ -72,7 +71,6 @@ final class DynamicTracepointTracerTests: XCTestCase { } XCTAssertEqual(tracer.spans[0].baggage.spanID, "span-id-fake-\(fileID)-\(fakeLine)") XCTAssertEqual(tracer.spans[1].baggage.spanID, "span-id-fake-\(fileID)-\(fakeNextLine)") - #endif } func test_adhoc_enableByFunction() { @@ -167,11 +165,12 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { var onEndSpan: (any Span) -> Void = { _ in } - func startAnySpan( + func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: DispatchWallTime, + at time: Clock.Instant, + clock: Clock, function: String, file fileID: String, line: UInt @@ -184,6 +183,7 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { let span = TracepointSpan( operationName: operationName, startTime: time, + clock: clock, baggage: baggage(), kind: kind, file: fileID, @@ -260,8 +260,8 @@ extension DynamicTracepointTestTracer { private var status: SpanStatus? - private let startTime: DispatchWallTime - private(set) var endTime: DispatchWallTime? + private let startTime: Int64 + private(set) var endTime: Int64? public var operationName: String private(set) var baggage: Baggage @@ -272,7 +272,8 @@ extension DynamicTracepointTestTracer { static func notRecording(file fileID: String, line: UInt) -> TracepointSpan { let span = TracepointSpan( operationName: "", - startTime: .now(), + startTime: TracerClock.now, + clock: TracerClock(), baggage: .topLevel, kind: .internal, file: fileID, @@ -283,16 +284,17 @@ extension DynamicTracepointTestTracer { return span } - init(operationName: String, - startTime: DispatchWallTime, - baggage: Baggage, - kind: SpanKind, - file fileID: String, - line: UInt, - onEnd: @escaping (TracepointSpan) -> Void) + init(operationName: String, + startTime: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), + baggage: Baggage, + kind: SpanKind, + file fileID: String, + line: UInt, + onEnd: @escaping (TracepointSpan) -> Void) { self.operationName = operationName - self.startTime = startTime + self.startTime = startTime.millisSinceEpoch self.baggage = baggage self.onEnd = onEnd self.kind = kind @@ -324,8 +326,8 @@ extension DynamicTracepointTestTracer { // nothing } - func end(at time: DispatchWallTime) { - self.endTime = time + func end(at time: Clock.Instant, clock: Clock) { + self.endTime = time.millisSinceEpoch self.onEnd(self) } } @@ -335,13 +337,14 @@ extension DynamicTracepointTestTracer { extension DynamicTracepointTestTracer: TracerProtocol { typealias TracerSpan = TracepointSpan - func startSpan(_ operationName: String, - baggage: @autoclosure () -> Baggage, - ofKind kind: Tracing.SpanKind, - at time: DispatchWallTime, - function: String, - file fileID: String, - line: UInt) -> TracepointSpan + func startSpan(_ operationName: String, + baggage: @autoclosure () -> Baggage, + ofKind kind: Tracing.SpanKind, + at time: Clock.Instant, + clock: Clock, + function: String, + file fileID: String, + line: UInt) -> TracepointSpan { let tracepoint = TracepointID(function: function, fileID: fileID, line: line) guard self.shouldRecord(tracepoint: tracepoint) else { @@ -351,6 +354,7 @@ extension DynamicTracepointTestTracer: TracerProtocol { let span = TracepointSpan( operationName: operationName, startTime: time, + clock: clock, baggage: baggage(), kind: kind, file: fileID, @@ -363,7 +367,5 @@ extension DynamicTracepointTestTracer: TracerProtocol { } #endif -#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 diff --git a/Tests/TracingTests/SpanTests.swift b/Tests/TracingTests/SpanTests.swift index 1ddd03b1..59307b54 100644 --- a/Tests/TracingTests/SpanTests.swift +++ b/Tests/TracingTests/SpanTests.swift @@ -161,7 +161,7 @@ final class SpanTests: XCTestCase { let parent = TestSpan( operationName: "client", - startTime: .now(), + startTime: TracerClock.now, baggage: parentBaggage, kind: .client, onEnd: { _ in } @@ -169,7 +169,7 @@ final class SpanTests: XCTestCase { let childBaggage = Baggage.topLevel let child = TestSpan( operationName: "server", - startTime: .now(), + startTime: TracerClock.now, baggage: childBaggage, kind: .server, onEnd: { _ in } @@ -195,7 +195,7 @@ final class SpanTests: XCTestCase { let parent = TestSpan( operationName: "client", - startTime: .now(), + startTime: TracerClock.now, baggage: parentBaggage, kind: .client, onEnd: { _ in } @@ -203,7 +203,7 @@ final class SpanTests: XCTestCase { let childBaggage = Baggage.topLevel let child = TestSpan( operationName: "server", - startTime: .now(), + startTime: TracerClock.now, baggage: childBaggage, kind: .server, onEnd: { _ in } diff --git a/Tests/TracingTests/TestTracer.swift b/Tests/TracingTests/TestTracer.swift index 44940f92..2d3f1ee8 100644 --- a/Tests/TracingTests/TestTracer.swift +++ b/Tests/TracingTests/TestTracer.swift @@ -23,11 +23,12 @@ final class TestTracer: LegacyTracerProtocol { private(set) var spans = [TestSpan]() var onEndSpan: (TestSpan) -> Void = { _ in } - func startAnySpan( + func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: DispatchWallTime, + at time: Clock.Instant, + clock: Clock, function: String, file fileID: String, line: UInt @@ -66,11 +67,12 @@ final class TestTracer: LegacyTracerProtocol { #if swift(>=5.7.0) extension TestTracer: TracerProtocol { - func startSpan( + func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: DispatchWallTime, + at time: Clock.Instant, + clock: Clock, function: String, file fileID: String, line: UInt @@ -124,8 +126,8 @@ final class TestSpan: Span { private var status: SpanStatus? - private let startTime: DispatchWallTime - private(set) var endTime: DispatchWallTime? + private let startTime: Int64 + private(set) var endTime: Int64? private(set) var recordedErrors: [(Error, SpanAttributes)] = [] @@ -152,13 +154,13 @@ final class TestSpan: Span { init( operationName: String, - startTime: DispatchWallTime, + startTime: some TracerInstantProtocol, baggage: Baggage, kind: SpanKind, onEnd: @escaping (TestSpan) -> Void ) { self.operationName = operationName - self.startTime = startTime + self.startTime = startTime.millisSinceEpoch self.baggage = baggage self.onEnd = onEnd self.kind = kind @@ -181,8 +183,8 @@ final class TestSpan: Span { self.recordedErrors.append((error, attributes)) } - func end(at time: DispatchWallTime) { - self.endTime = time + func end(at time: Clock.Instant = Clock.now, clock: Clock = TracerClock()) { + self.endTime = time.millisSinceEpoch self.onEnd(self) } } diff --git a/Tests/TracingTests/TracedLockTests.swift b/Tests/TracingTests/TracedLockTests.swift index 1aff5988..dd21716c 100644 --- a/Tests/TracingTests/TracedLockTests.swift +++ b/Tests/TracingTests/TracedLockTests.swift @@ -60,11 +60,12 @@ enum TaskIDKey: BaggageKey { /// Only intended to be used in single-threaded testing. private final class TracedLockPrintlnTracer: LegacyTracerProtocol { - func startAnySpan( + func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: DispatchWallTime, + at time: Clock.Instant = Clock.now, + clock: Clock = TracerClock(), function: String, file fileID: String, line: UInt @@ -102,8 +103,8 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { private var status: SpanStatus? - private let startTime: DispatchWallTime - private(set) var endTime: DispatchWallTime? + private let startTimeMillis: Int64 + private(set) var endTimeMillis: Int64? var operationName: String let baggage: Baggage @@ -126,16 +127,16 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { init( operationName: String, - startTime: DispatchWallTime, + startTime: some TracerInstantProtocol, kind: SpanKind, baggage: Baggage ) { self.operationName = operationName - self.startTime = startTime + self.startTimeMillis = startTime.millisSinceEpoch self.baggage = baggage self.kind = kind - print(" span [\(self.operationName): \(self.baggage[TaskIDKey.self] ?? "no-name")] @ \(self.startTime): start") + print(" span [\(self.operationName): \(self.baggage[TaskIDKey.self] ?? "no-name")] @ \(self.startTimeMillis): start") } func setStatus(_ status: SpanStatus) { @@ -153,8 +154,8 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { func recordError(_ error: Error, attributes: SpanAttributes) {} - func end(at time: DispatchWallTime) { - self.endTime = time + func end(at time: Clock.Instant, clock: Clock) { + self.endTimeMillis = time.millisSinceEpoch print(" span [\(self.operationName): \(self.baggage[TaskIDKey.self] ?? "no-name")] @ \(time): end") } } @@ -162,11 +163,12 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { #if swift(>=5.7.0) extension TracedLockPrintlnTracer: TracerProtocol { - func startSpan( + func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: DispatchWallTime, + at time: Clock.Instant, + clock: Clock, function: String, file fileID: String, line: UInt diff --git a/Tests/TracingTests/TracerTests.swift b/Tests/TracingTests/TracerTests.swift index 8cff8df0..15de84e7 100644 --- a/Tests/TracingTests/TracerTests.swift +++ b/Tests/TracingTests/TracerTests.swift @@ -351,7 +351,25 @@ final class TracerTests: XCTestCase { #endif } - #if swift(>=5.5) && canImport(_Concurrency) + #if swift(>=5.7.0) +// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) + /// Helper method to execute async operations until we can use async tests (currently incompatible with the generated LinuxMain file). + /// - Parameter operation: The operation to test. + func testAsync(_ operation: @escaping () async throws -> Void) rethrows { + let group = DispatchGroup() + group.enter() + Task.detached { + do { + try await operation() + } catch { + throw error + } + group.leave() + } + group.wait() + } + + #elseif swift(>=5.5) && canImport(_Concurrency) @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) /// Helper method to execute async operations until we can use async tests (currently incompatible with the generated LinuxMain file). /// - Parameter operation: The operation to test. From c335f47af633adc34fa5d2ec407a51687bf29331 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Fri, 24 Mar 2023 11:56:22 +0900 Subject: [PATCH 2/9] add test comparing our time to Date() --- Tests/TracingTests/TracerTimeTests.swift | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Tests/TracingTests/TracerTimeTests.swift diff --git a/Tests/TracingTests/TracerTimeTests.swift b/Tests/TracingTests/TracerTimeTests.swift new file mode 100644 index 00000000..cb7a096a --- /dev/null +++ b/Tests/TracingTests/TracerTimeTests.swift @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Distributed Tracing open source project +// +// Copyright (c) 2020-2021 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 +// +//===----------------------------------------------------------------------===// + +import InstrumentationBaggage +import Tracing +import struct Foundation.Date +import XCTest + +final class TracerTimeTests: XCTestCase { + func testTracerTime() { + let t = TracerClock.now + let d = Date() + XCTAssertEqual( + (Double(t.millisSinceEpoch) / 1000), // seconds + d.timeIntervalSince1970, // seconds + accuracy: 10) + } +} \ No newline at end of file From 564a3b337f81100f9f2cf2c82a749e9a46793384 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 28 Mar 2023 23:39:21 +0900 Subject: [PATCH 3/9] move to just requiring clock --- Package.swift | 5 - .../include/tracing_time_support.h | 16 --- .../tracing_time_support.c | 46 ------- Sources/Tracing/NoOpTracer.swift | 4 +- Sources/Tracing/SpanProtocol.swift | 13 +- Sources/Tracing/Tracer.swift | 107 ++++++---------- Sources/Tracing/TracerProtocol+Legacy.swift | 121 +++++++----------- Sources/Tracing/TracerProtocol.swift | 42 ++++-- Sources/Tracing/TracingTime.swift | 108 ++++------------ .../DynamicTracepointTracerTests.swift | 38 +++--- Tests/TracingTests/TestTracer.swift | 18 ++- Tests/TracingTests/TracedLockTests.swift | 13 +- Tests/TracingTests/TracerTimeTests.swift | 52 +++++++- 13 files changed, 233 insertions(+), 350 deletions(-) delete mode 100644 Sources/CTracingTimeSupport/include/tracing_time_support.h delete mode 100644 Sources/CTracingTimeSupport/tracing_time_support.c diff --git a/Package.swift b/Package.swift index 426dba0d..435c511e 100644 --- a/Package.swift +++ b/Package.swift @@ -41,13 +41,8 @@ let package = Package( name: "Tracing", dependencies: [ .target(name: "Instrumentation"), - .target(name: "CTracingTimeSupport"), ] ), - .target( - name: "CTracingTimeSupport", - dependencies: [] - ), .testTarget( name: "TracingTests", dependencies: [ diff --git a/Sources/CTracingTimeSupport/include/tracing_time_support.h b/Sources/CTracingTimeSupport/include/tracing_time_support.h deleted file mode 100644 index 430c9b5d..00000000 --- a/Sources/CTracingTimeSupport/include/tracing_time_support.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// Created by Konrad 'ktoso' Malawski on 3/23/23. -// - -#ifndef SWIFT_DISTRIBUTED_TRACING_TRACING_TIME_SUPPORT_H -#define SWIFT_DISTRIBUTED_TRACING_TRACING_TIME_SUPPORT_H - - -typedef double SDTTimeInterval; -typedef SDTTimeInterval SDTAbsoluteTime; -/* absolute time is the time interval since the reference date */ -/* the reference date (epoch) is 00:00:00 1 January 2001. */ - -SDTAbsoluteTime SDTAbsoluteTimeGetCurrent(); - -#endif //SWIFT_DISTRIBUTED_TRACING_TRACING_TIME_SUPPORT_H diff --git a/Sources/CTracingTimeSupport/tracing_time_support.c b/Sources/CTracingTimeSupport/tracing_time_support.c deleted file mode 100644 index 3dd33a59..00000000 --- a/Sources/CTracingTimeSupport/tracing_time_support.c +++ /dev/null @@ -1,46 +0,0 @@ -// -// Created by Konrad 'ktoso' Malawski on 3/23/23. -// - -#include "include/tracing_time_support.h" - -#if __HAS_DISPATCH__ -#include -#else - #ifndef NSEC_PER_SEC - #define NSEC_PER_SEC 1000000000UL - #endif -#endif - -//#if TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD || TARGET_OS_WASI -#include -//#endif - -const SDTTimeInterval kCFAbsoluteTimeIntervalSince1970 = 978307200.0L; -const SDTTimeInterval kCFAbsoluteTimeIntervalSince1904 = 3061152000.0L; - - -//#if TARGET_OS_WIN32 -//CFAbsoluteTime CFAbsoluteTimeGetCurrent(void) { -// SYSTEMTIME stTime; -// FILETIME ftTime; -// -// GetSystemTime(&stTime); -// SystemTimeToFileTime(&stTime, &ftTime); -// -// // 100ns intervals since NT Epoch -// uint64_t result = ((uint64_t)ftTime.dwHighDateTime << 32) -// | ((uint64_t)ftTime.dwLowDateTime << 0); -// return result * 1.0e-7 - kCFAbsoluteTimeIntervalSince1601; -//} -//#else -SDTAbsoluteTime SDTAbsoluteTimeGetCurrent() { - SDTAbsoluteTime ret; - struct timeval tv; - gettimeofday(&tv, NULL); - ret = (SDTTimeInterval)tv.tv_sec - kCFAbsoluteTimeIntervalSince1970; - ret += (1.0E-6 * (SDTTimeInterval)tv.tv_usec); - return ret; -} - -//#endif \ No newline at end of file diff --git a/Sources/Tracing/NoOpTracer.swift b/Sources/Tracing/NoOpTracer.swift index 4d7e8dde..32266f72 100644 --- a/Sources/Tracing/NoOpTracer.swift +++ b/Sources/Tracing/NoOpTracer.swift @@ -26,7 +26,6 @@ public struct NoOpTracer: LegacyTracerProtocol { public func startAnySpan(_ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, @@ -85,7 +84,7 @@ public struct NoOpTracer: LegacyTracerProtocol { } } - public func end(at time: Clock.Instant, clock: Clock) { + public func end(clock: Clock) { // ignore } } @@ -97,7 +96,6 @@ extension NoOpTracer: TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, diff --git a/Sources/Tracing/SpanProtocol.swift b/Sources/Tracing/SpanProtocol.swift index 8be5e9bc..bfd76696 100644 --- a/Sources/Tracing/SpanProtocol.swift +++ b/Sources/Tracing/SpanProtocol.swift @@ -101,7 +101,7 @@ public protocol Span: _SwiftTracingSendableSpan { /// - Parameter time: The `DispatchWallTime` at which the span ended. /// /// - SeeAlso: `Span.end()` which automatically uses the "current" time. - func end(at time: Clock.Instant, clock: Clock) + func end(clock: Clock) } extension Span { @@ -120,7 +120,7 @@ extension Span { /// - SeeAlso: ``end(at:)`` which allows passing in a specific time, e.g. if the operation was ended and recorded somewhere and we need to post-factum record it. /// Generally though prefer using the ``end()`` version of this API in user code and structure your system such that it can be called in the right place and time. public func end() { - self.end(at: TracerClock.now, clock: TracerClock()) + self.end(clock: TracerClock()) } /// Adds a ``SpanLink`` between this `Span` and the given `Span`. @@ -154,17 +154,20 @@ public struct SpanEvent: Equatable { public var attributes: SpanAttributes /// The `DispatchWallTime` at which this event occurred. - public let time: DispatchWallTime + public let time: UInt64 /// Create a new `SpanEvent`. /// - Parameters: /// - name: The human-readable name of this event. /// - attributes: attributes describing this event. Defaults to no attributes. /// - time: The `DispatchWallTime` at which this event occurred. Defaults to `.now()`. - public init(name: String, attributes: SpanAttributes = [:], at time: DispatchWallTime = .now()) { + public init(name: String, + attributes: SpanAttributes = [:], + clock: Clock = TracerClock()) + { self.name = name self.attributes = attributes - self.time = time + self.time = clock.now.millisSinceEpoch } } diff --git a/Sources/Tracing/Tracer.swift b/Sources/Tracing/Tracer.swift index 4b1709d3..e7c7780f 100644 --- a/Sources/Tracing/Tracer.swift +++ b/Sources/Tracing/Tracer.swift @@ -46,7 +46,6 @@ extension Tracer { /// - 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 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. @@ -55,7 +54,6 @@ extension Tracer { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: TracerClock.Instant = TracerClock.now, function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -65,7 +63,6 @@ extension Tracer { #if swift(>=5.7.0) InstrumentationSystem.tracer.startSpan( operationName, - at: time, clock: TracerClock(), function: function, file: fileID, @@ -76,7 +73,7 @@ extension Tracer { operationName, baggage: baggage(), ofKind: kind, - at: time, + at: { $0.now }, clock: TracerClock(), function: function, file: fileID, @@ -114,7 +111,6 @@ extension Tracer { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, @@ -125,7 +121,8 @@ extension Tracer { #if swift(>=5.7.0) InstrumentationSystem.tracer.startSpan( operationName, - at: time, + baggage: baggage(), + ofKind: kind, clock: clock, function: function, file: fileID, @@ -136,7 +133,7 @@ extension Tracer { operationName, baggage: baggage(), ofKind: kind, - at: time, + clock: clock, function: function, file: fileID, line: line @@ -181,6 +178,42 @@ extension Tracer { try InstrumentationSystem.legacyTracer.withAnySpan( operationName, ofKind: kind, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) { anySpan in + try operation(anySpan) + } + #else + try InstrumentationSystem.legacyTracer.withAnySpan( + operationName, + ofKind: kind, + function: function, + file: fileID, + line: line + ) { anySpan in + try operation(anySpan) + } + #endif + } + + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage + public static func withSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + clock: Clock = TracerClock(), + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Span) throws -> T + ) rethrows -> T { + #if swift(>=5.7.0) + try InstrumentationSystem.legacyTracer.withAnySpan( + operationName, + ofKind: kind, + clock: clock, function: function, file: fileID, line: line @@ -191,6 +224,7 @@ extension Tracer { try InstrumentationSystem.legacyTracer.withAnySpan( operationName, ofKind: kind, + clock: clock, function: function, file: fileID, line: line @@ -216,19 +250,17 @@ extension Tracer { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. /// - 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(>=5.7.0) public static func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: TracerClock.Instant = TracerClock.now, function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -238,7 +270,6 @@ extension Tracer { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: TracerClock(), function: function, file: fileID, @@ -247,39 +278,11 @@ extension Tracer { try await operation(anySpan) } } - #else // TODO: remove this if/else when we require 5.7 - @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) - public static func withSpan( - _ operationName: String, - baggage: @autoclosure () -> Baggage = .current ?? .topLevel, - ofKind kind: SpanKind = .internal, - at time: TracerClock.Instant = .now, - function: String = #function, - file fileID: String = #fileID, - line: UInt = #line, - @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T - ) async rethrows -> T { - try await InstrumentationSystem.legacyTracer.withAnySpan( - operationName, - baggage: baggage(), - ofKind: kind, - at: time, - clock: TracerClock(), - function: function, - file: fileID, - line: line - ) { anySpan in - try await operation(anySpan) - } - } - #endif - #if swift(>=5.7.0) public static func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, @@ -290,7 +293,6 @@ extension Tracer { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: clock, function: function, file: fileID, @@ -299,29 +301,4 @@ extension Tracer { try await operation(anySpan) } } - #else // TODO: remove this if/else when we require 5.7 - @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) - public static func withSpan( - _ operationName: String, - baggage: @autoclosure () -> Baggage = .current ?? .topLevel, - ofKind kind: SpanKind = .internal, - at time: DispatchWallTime = .now(), - function: String = #function, - file fileID: String = #fileID, - line: UInt = #line, - @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T - ) async rethrows -> T { - try await InstrumentationSystem.legacyTracer.withAnySpan( - operationName, - baggage: baggage(), - ofKind: kind, - at: time, - function: function, - file: fileID, - line: line - ) { anySpan in - try await operation(anySpan) - } - } - #endif } diff --git a/Sources/Tracing/TracerProtocol+Legacy.swift b/Sources/Tracing/TracerProtocol+Legacy.swift index 74f0f527..389fad85 100644 --- a/Sources/Tracing/TracerProtocol+Legacy.swift +++ b/Sources/Tracing/TracerProtocol+Legacy.swift @@ -51,7 +51,6 @@ public protocol LegacyTracerProtocol: InstrumentProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, @@ -101,11 +100,11 @@ extension LegacyTracerProtocol { /// - 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. - public func startAnySpan( + public func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: TracerClock.Instant = TracerClock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -114,20 +113,17 @@ extension LegacyTracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: TracerClock.now, - clock: TracerClock(), + clock: clock, function: function, file: fileID, line: line ) } - public func startAnySpan( + public func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -136,8 +132,7 @@ extension LegacyTracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: clock.now, - clock: clock, + clock: TracerClock(), function: function, file: fileID, line: line @@ -177,11 +172,11 @@ extension LegacyTracerProtocol { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) - public func withAnySpan( + public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: TracerClock.Instant = TracerClock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -191,8 +186,7 @@ extension LegacyTracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, - clock: TracerClock(), + clock: clock, function: function, file: fileID, line: line @@ -208,36 +202,25 @@ extension LegacyTracerProtocol { } } - public func withAnySpan( + public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, _ operation: (any Span) throws -> T ) rethrows -> T { - let span = self.startAnySpan( + try self.withAnySpan( operationName, baggage: baggage(), ofKind: kind, - at: time, - clock: clock, + clock: TracerClock(), function: function, file: fileID, - line: line + line: line, + operation ) - defer { span.end() } - do { - return try Baggage.$current.withValue(span.baggage) { - try operation(span) - } - } catch { - span.recordError(error) - throw error // rethrow - } } /// Start a new ``Span`` and automatically end when the `operation` completes, @@ -273,11 +256,11 @@ extension LegacyTracerProtocol { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) - public func withAnySpan( + public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: TracerClock.Instant = TracerClock.now, + clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -287,8 +270,7 @@ extension LegacyTracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, - clock: TracerClock(), + clock: clock, function: function, file: fileID, line: line @@ -304,12 +286,10 @@ extension LegacyTracerProtocol { } } - public func withAnySpan( + public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -319,8 +299,7 @@ extension LegacyTracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, - clock: clock, + clock: TracerClock(), function: function, file: fileID, line: line @@ -335,6 +314,36 @@ extension LegacyTracerProtocol { throw error // rethrow } } + +// public func withAnySpan( +// _ operationName: String, +// baggage: @autoclosure () -> Baggage = .current ?? .topLevel, +// ofKind kind: SpanKind = .internal, +// clock: Clock = TracerClock(), +// function: String = #function, +// file fileID: String = #fileID, +// line: UInt = #line, +// _ operation: (any Span) async throws -> T +// ) async rethrows -> T { +// let span = self.startAnySpan( +// operationName, +// baggage: baggage(), +// ofKind: kind, +// clock: clock, +// function: function, +// file: fileID, +// line: line +// ) +// defer { span.end() } +// do { +// return try await Baggage.$current.withValue(span.baggage) { +// try await operation(span) +// } +// } catch { +// span.recordError(error) +// throw error // rethrow +// } +// } } #if swift(>=5.7.0) @@ -383,7 +392,7 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: TracerClock.now, + clock: TracerClock(), function: function, file: fileID, line: line @@ -423,7 +432,6 @@ extension TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, @@ -433,7 +441,6 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: clock, function: function, file: fileID, @@ -478,7 +485,6 @@ extension TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, @@ -489,7 +495,6 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: clock, function: function, file: fileID, @@ -532,12 +537,10 @@ extension TracerProtocol { /// - 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(>=5.7.0) public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, @@ -548,7 +551,6 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: clock, function: function, file: fileID, @@ -557,30 +559,5 @@ extension TracerProtocol { try await operation(span) } } - #else // TODO: remove this if/else when we require 5.7; it is only here to add @_unsafeInheritExecutor - @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) - public func withAnySpan( - _ operationName: String, - baggage: @autoclosure () -> Baggage = .current ?? .topLevel, - ofKind kind: SpanKind = .internal, - at time: some TracerInstantProtocol, - function: String = #function, - file fileID: String = #fileID, - line: UInt = #line, - @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T - ) async rethrows -> T { - try await self.withSpan( - operationName, - baggage: baggage(), - ofKind: kind, - at: time, - function: function, - file: fileID, - line: line - ) { span in - try await operation(span) - } - } - #endif } #endif diff --git a/Sources/Tracing/TracerProtocol.swift b/Sources/Tracing/TracerProtocol.swift index 4b53889f..2e482fb5 100644 --- a/Sources/Tracing/TracerProtocol.swift +++ b/Sources/Tracing/TracerProtocol.swift @@ -55,7 +55,6 @@ public protocol TracerProtocol: LegacyTracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, @@ -85,7 +84,7 @@ extension TracerProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. @@ -93,7 +92,6 @@ extension TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, @@ -103,7 +101,6 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: clock, function: function, file: fileID, @@ -132,7 +129,7 @@ extension TracerProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. @@ -143,7 +140,6 @@ extension TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, @@ -154,7 +150,6 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: clock, function: function, file: fileID, @@ -175,7 +170,6 @@ extension TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: TracerClock.Instant = TracerClock.now, function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -185,7 +179,6 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: TracerClock(), function: function, file: fileID, @@ -225,11 +218,39 @@ extension TracerProtocol { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) + public func withSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + @_inheritActorContext @_implicitSelfCapture _ operation: (TracerSpan) async throws -> T + ) async rethrows -> T { + let span = self.startSpan( + operationName, + baggage: baggage(), + ofKind: kind, + clock: TracerClock(), + function: function, + file: fileID, + line: line + ) + defer { span.end() } + do { + return try await Baggage.$current.withValue(span.baggage) { + try await operation(span) + } + } catch { + span.recordError(error) + throw error // rethrow + } + } + public func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, @@ -240,7 +261,6 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - at: time, clock: clock, function: function, file: fileID, diff --git a/Sources/Tracing/TracingTime.swift b/Sources/Tracing/TracingTime.swift index 60722234..8a7dbf9d 100644 --- a/Sources/Tracing/TracingTime.swift +++ b/Sources/Tracing/TracingTime.swift @@ -17,7 +17,6 @@ import Dispatch @_exported import Instrumentation @_exported import InstrumentationBaggage -// FIXME: mirrors DurationProtocol public protocol SwiftDistributedTracingDurationProtocol: Comparable, AdditiveArithmetic, Sendable { static func / (_ lhs: Self, _ rhs: Int) -> Self static func /= (_ lhs: inout Self, _ rhs: Int) @@ -33,69 +32,50 @@ extension SwiftDistributedTracingDurationProtocol { } } -// #if swift(>=5.7.0) -// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) -// public protocol SwiftDistributedTracingInstantProtocol: InstantProtocol {} -// #else public protocol SwiftDistributedTracingInstantProtocol: Comparable, Hashable, Sendable { // associatedtype Duration: SwiftDistributedTracingDurationProtocol } -// #endif - -// #if swift(>=5.7.0) -// public protocol SwiftDistributedTracingClock: Clock {} -// #else -public protocol SwiftDistributedTracingClock: Sendable {} -// #endif - public protocol TracerInstantProtocol: SwiftDistributedTracingInstantProtocol { /// Representation of this instant as the number of milliseconds since UNIX Epoch (January 1st 1970) @inlinable - var millisSinceEpoch: Int64 { get } + var millisSinceEpoch: UInt64 { get } } -public protocol TracerClockProtocol: SwiftDistributedTracingClock { - // associatedtype Duration where Self.Duration == Self.Instant.Duration +/// A specialized clock protocol for purposes of tracing. +/// +/// A tracer clock must ONLY be able to offer the current time in the form of an unix timestamp. +/// It does not have to allow sleeping, nor is it interchangeable with other notions of clocks (e.g. such as monotonic time etc). +/// +/// If the standard library, or foundation, or someone else were to implement an UTCClock or UNIXTimestampClock, +/// they can be made to conform to `TracerClockProtocol`. +/// +/// The primary purpose of this clock protocol is to enable mocking the "now" time when starting and ending spans, +/// especially when the system is already using some notion of simulated or mocked time, such that traces are +/// expressed using the same notion of time. +public protocol TracerClockProtocol { associatedtype Instant: TracerInstantProtocol - static var now: Self.Instant { get } var now: Self.Instant { get } } -extension TracerClock { - // public typealias Duration = Swift.Duration -} - +/// A basic "timestamp clock" implementation that is able to five the current time as an unix timestamp. public struct TracerClock: TracerClockProtocol { - // LIKE FOUNDATION + public typealias Instant = Timestamp internal typealias TimeInterval = Double public init() { // empty } - public struct Instant: TracerInstantProtocol { -// #if swift(>=5.7.0) -// public typealias Duration = Swift.Duration -// #endif - - public var millisSinceEpoch: Int64 + public struct Timestamp: TracerInstantProtocol { + /// Milliseconds since January 1st, 1970, also known as "unix epoch". + public var millisSinceEpoch: UInt64 - internal init(millisSinceEpoch: Int64) { + internal init(millisSinceEpoch: UInt64) { self.millisSinceEpoch = millisSinceEpoch } -// public func advanced(by duration: Self.Duration) -> Self { -// var copy = self -// copy.millisSinceEpoch += duration.milliseconds -// return copy -// } -// -// public func duration(to other: Self) -> Self.Duration { -// Duration.milliseconds(self.millisSinceEpoch - other.millisSinceEpoch) -// } - public static func < (lhs: Instant, rhs: Instant) -> Bool { lhs.millisSinceEpoch < rhs.millisSinceEpoch } @@ -113,53 +93,17 @@ public struct TracerClock: TracerClockProtocol { TracerClock().now } - /// The number of seconds from 1 January 1970 to the reference date, 1 January 2001. - internal static let timeIntervalBetween1970AndReferenceDate: TimeInterval = 978_307_200.0 - - /// The interval between 00:00:00 UTC on 1 January 2001 and the current date and time. - internal static var timeIntervalSinceReferenceDate: TimeInterval { - CTracingTimeSupport.SDTAbsoluteTimeGetCurrent() - } - public var now: Self.Instant { - let sinceReference = TracerClock.timeIntervalSinceReferenceDate - let between1970AndReference = TracerClock.timeIntervalBetween1970AndReferenceDate - let nowDouble = sinceReference + between1970AndReference - let nowMillis = Int64((nowDouble * 1000).rounded()) + var ts = timespec() + clock_gettime(CLOCK_REALTIME, &ts) + /// We use unsafe arithmetic here because `UInt64.max` nanoseconds is more than 580 years, + /// and the odds that this code will still be running 530 years from now is very, very low, + /// so as a practical matter this will never overflow. + let nowNanos = UInt64(ts.tv_sec) &* 1_000_000_000 &+ UInt64(ts.tv_nsec) + let nowMillis = UInt64(nowNanos / 1_000_000) // nanos to millis return Instant(millisSinceEpoch: nowMillis) } - - // #if swift(>=5.7.0) - // public var minimumResolution: Self.Duration { -// .milliseconds(1) - // } - // #endif -} - -// #if swift(>=5.7.0) -// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) -// extension TracerClock: Clock { -// -// @available(*, deprecated, message: "TracerClock is not able to sleep()") -// public func sleep(until deadline: Self.Instant, tolerance: Instant.Duration?) async throws { -// fatalError("\(TracerClock.self) does not implement sleep() capabilities!") -// } -// -// } -// #endif - -extension DispatchWallTime { - internal init(millisSinceEpoch: Int64) { - let nanoSinceEpoch = UInt64(millisSinceEpoch) * 1_000_000 - let seconds = UInt64(nanoSinceEpoch / 1_000_000_000) - let nanoseconds = nanoSinceEpoch - (seconds * 1_000_000_000) - self.init(timespec: timespec(tv_sec: Int(seconds), tv_nsec: Int(nanoseconds))) - } - - internal var millisSinceEpoch: Int64 { - Int64(bitPattern: self.rawValue) / -1_000_000 - } } #if swift(>=5.7.0) diff --git a/Tests/TracingTests/DynamicTracepointTracerTests.swift b/Tests/TracingTests/DynamicTracepointTracerTests.swift index 65a978e2..1ead8237 100644 --- a/Tests/TracingTests/DynamicTracepointTracerTests.swift +++ b/Tests/TracingTests/DynamicTracepointTracerTests.swift @@ -169,7 +169,6 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, @@ -182,13 +181,12 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { let span = TracepointSpan( operationName: operationName, - startTime: time, - clock: clock, + startTime: clock.now, baggage: baggage(), kind: kind, file: fileID, line: line, - onEnd: onEndSpan + onEnd: self.onEndSpan ) self.spans.append(span) return span @@ -260,8 +258,8 @@ extension DynamicTracepointTestTracer { private var status: SpanStatus? - private let startTime: Int64 - private(set) var endTime: Int64? + private let startTime: UInt64 + private(set) var endTime: UInt64? public var operationName: String private(set) var baggage: Baggage @@ -272,8 +270,7 @@ extension DynamicTracepointTestTracer { static func notRecording(file fileID: String, line: UInt) -> TracepointSpan { let span = TracepointSpan( operationName: "", - startTime: TracerClock.now, - clock: TracerClock(), + startTime: TracerClock().now, baggage: .topLevel, kind: .internal, file: fileID, @@ -284,14 +281,13 @@ extension DynamicTracepointTestTracer { return span } - init(operationName: String, - startTime: Clock.Instant = Clock.now, - clock: Clock = TracerClock(), - baggage: Baggage, - kind: SpanKind, - file fileID: String, - line: UInt, - onEnd: @escaping (TracepointSpan) -> Void) + init(operationName: String, + startTime: some TracerInstantProtocol, + baggage: Baggage, + kind: SpanKind, + file fileID: String, + line: UInt, + onEnd: @escaping (TracepointSpan) -> Void) { self.operationName = operationName self.startTime = startTime.millisSinceEpoch @@ -326,8 +322,8 @@ extension DynamicTracepointTestTracer { // nothing } - func end(at time: Clock.Instant, clock: Clock) { - self.endTime = time.millisSinceEpoch + func end(clock: Clock) { + self.endTime = clock.now.millisSinceEpoch self.onEnd(self) } } @@ -340,7 +336,6 @@ extension DynamicTracepointTestTracer: TracerProtocol { func startSpan(_ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: Tracing.SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, @@ -353,13 +348,12 @@ extension DynamicTracepointTestTracer: TracerProtocol { let span = TracepointSpan( operationName: operationName, - startTime: time, - clock: clock, + startTime: clock.now, baggage: baggage(), kind: kind, file: fileID, line: line, - onEnd: onEndSpan + onEnd: self.onEndSpan ) self.spans.append(span) return span diff --git a/Tests/TracingTests/TestTracer.swift b/Tests/TracingTests/TestTracer.swift index 2d3f1ee8..653be50a 100644 --- a/Tests/TracingTests/TestTracer.swift +++ b/Tests/TracingTests/TestTracer.swift @@ -27,7 +27,6 @@ final class TestTracer: LegacyTracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, @@ -35,10 +34,10 @@ final class TestTracer: LegacyTracerProtocol { ) -> any Span { let span = TestSpan( operationName: operationName, - startTime: time, + startTime: clock.now, baggage: baggage(), kind: kind, - onEnd: onEndSpan + onEnd: self.onEndSpan ) self.spans.append(span) return span @@ -71,7 +70,6 @@ extension TestTracer: TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, @@ -79,10 +77,10 @@ extension TestTracer: TracerProtocol { ) -> TestSpan { let span = TestSpan( operationName: operationName, - startTime: time, + startTime: clock.now, baggage: baggage(), kind: kind, - onEnd: onEndSpan + onEnd: self.onEndSpan ) self.spans.append(span) return span @@ -126,8 +124,8 @@ final class TestSpan: Span { private var status: SpanStatus? - private let startTime: Int64 - private(set) var endTime: Int64? + public let startTime: UInt64 + public private(set) var endTime: UInt64? private(set) var recordedErrors: [(Error, SpanAttributes)] = [] @@ -183,8 +181,8 @@ final class TestSpan: Span { self.recordedErrors.append((error, attributes)) } - func end(at time: Clock.Instant = Clock.now, clock: Clock = TracerClock()) { - self.endTime = time.millisSinceEpoch + func end(clock: Clock = TracerClock()) { + self.endTime = clock.now.millisSinceEpoch self.onEnd(self) } } diff --git a/Tests/TracingTests/TracedLockTests.swift b/Tests/TracingTests/TracedLockTests.swift index dd21716c..14c4ac53 100644 --- a/Tests/TracingTests/TracedLockTests.swift +++ b/Tests/TracingTests/TracedLockTests.swift @@ -64,7 +64,6 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant = Clock.now, clock: Clock = TracerClock(), function: String, file fileID: String, @@ -72,7 +71,7 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { ) -> any Span { TracedLockPrintlnSpan( operationName: operationName, - startTime: time, + startTime: clock.now, kind: kind, baggage: baggage() ) @@ -103,8 +102,8 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { private var status: SpanStatus? - private let startTimeMillis: Int64 - private(set) var endTimeMillis: Int64? + private let startTimeMillis: UInt64 + private(set) var endTimeMillis: UInt64? var operationName: String let baggage: Baggage @@ -154,7 +153,8 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { func recordError(_ error: Error, attributes: SpanAttributes) {} - func end(at time: Clock.Instant, clock: Clock) { + func end(clock: Clock) { + let time = clock.now self.endTimeMillis = time.millisSinceEpoch print(" span [\(self.operationName): \(self.baggage[TaskIDKey.self] ?? "no-name")] @ \(time): end") } @@ -167,7 +167,6 @@ extension TracedLockPrintlnTracer: TracerProtocol { _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - at time: Clock.Instant, clock: Clock, function: String, file fileID: String, @@ -175,7 +174,7 @@ extension TracedLockPrintlnTracer: TracerProtocol { ) -> TracedLockPrintlnSpan { TracedLockPrintlnSpan( operationName: operationName, - startTime: time, + startTime: clock.now, kind: kind, baggage: baggage() ) diff --git a/Tests/TracingTests/TracerTimeTests.swift b/Tests/TracingTests/TracerTimeTests.swift index cb7a096a..9eda66d7 100644 --- a/Tests/TracingTests/TracerTimeTests.swift +++ b/Tests/TracingTests/TracerTimeTests.swift @@ -12,18 +12,58 @@ // //===----------------------------------------------------------------------===// -import InstrumentationBaggage -import Tracing import struct Foundation.Date +@testable import Instrumentation +import Tracing import XCTest final class TracerTimeTests: XCTestCase { + override class func tearDown() { + super.tearDown() + InstrumentationSystem.bootstrapInternal(nil) + } + func testTracerTime() { let t = TracerClock.now let d = Date() XCTAssertEqual( - (Double(t.millisSinceEpoch) / 1000), // seconds - d.timeIntervalSince1970, // seconds - accuracy: 10) + Double(t.millisSinceEpoch) / 1000, // seconds + d.timeIntervalSince1970, // seconds + accuracy: 10 + ) + } + + func testMockTimeStartSpan() { + let tracer = TestTracer() + InstrumentationSystem.bootstrapInternal(tracer) + defer { + InstrumentationSystem.bootstrapInternal(NoOpTracer()) + } + + let mockClock = MockClock() + mockClock.setTime(13) + let span: TestSpan = tracer.startSpan("start", clock: mockClock) + XCTAssertEqual(span.startTime, 13) + } +} + +final class MockClock: TracerClockProtocol { + var _now: UInt64 = 0 + + init() {} + + func setTime(_ time: UInt64) { + self._now = time + } + + struct Instant: TracerInstantProtocol { + var millisSinceEpoch: UInt64 + static func < (lhs: MockClock.Instant, rhs: MockClock.Instant) -> Bool { + lhs.millisSinceEpoch < rhs.millisSinceEpoch + } + } + + var now: Instant { + Instant(millisSinceEpoch: self._now) } -} \ No newline at end of file +} From 2a0090e6cfe090f3773de6021b9e808668a59d04 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 28 Mar 2023 23:40:37 +0900 Subject: [PATCH 4/9] remove old import --- Sources/Tracing/TracingTime.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/Tracing/TracingTime.swift b/Sources/Tracing/TracingTime.swift index 8a7dbf9d..0953031b 100644 --- a/Sources/Tracing/TracingTime.swift +++ b/Sources/Tracing/TracingTime.swift @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -import CTracingTimeSupport import Dispatch @_exported import Instrumentation @_exported import InstrumentationBaggage From 3fe6209d41d9c09b8f6322d37eb4d6436d4cfc0c Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 28 Mar 2023 23:45:23 +0900 Subject: [PATCH 5/9] linux imports --- Sources/Tracing/TracingTime.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/Tracing/TracingTime.swift b/Sources/Tracing/TracingTime.swift index 0953031b..2ab8399d 100644 --- a/Sources/Tracing/TracingTime.swift +++ b/Sources/Tracing/TracingTime.swift @@ -12,7 +12,12 @@ // //===----------------------------------------------------------------------===// -import Dispatch +#if os(Linux) +import Glibc +#else +import Darwin +#endif + @_exported import Instrumentation @_exported import InstrumentationBaggage From 4cdb0c0249f4e706008a8da609d2bba4c4510258 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 29 Mar 2023 13:35:13 +0900 Subject: [PATCH 6/9] Support 5.6 Swift --- Sources/Instrumentation/Instrument.swift | 2 +- .../InstrumentationSystem.swift | 2 +- Sources/Instrumentation/Locks.swift | 2 +- .../Instrumentation/MultiplexInstrument.swift | 2 +- Sources/Instrumentation/NoOpInstrument.swift | 2 +- .../InstrumentationSystem+Tracing.swift | 2 +- Sources/Tracing/NoOpTracer.swift | 20 +- Sources/Tracing/SpanProtocol.swift | 34 +- Sources/Tracing/Tracer.swift | 162 ++++----- Sources/Tracing/TracerProtocol+Legacy.swift | 195 ++--------- Sources/Tracing/TracerProtocol.swift | 25 +- Sources/Tracing/TracingTime.swift | 10 +- .../_TracingBenchmarkTools/ArgParser.swift | 2 +- .../BenchmarkCategory.swift | 2 +- .../BenchmarkTools.swift | 2 +- .../_TracingBenchmarkTools/DriverUtils.swift | 2 +- .../SpanAttributesDSLBenchmark.swift | 312 +++++++++--------- Sources/_TracingBenchmarks/main.swift | 74 ++--- .../InstrumentTests.swift | 2 +- .../InstrumentationSystemTests.swift | 2 +- .../DynamicTracepointTracerTests.swift | 36 +- Tests/TracingTests/SpanTests.swift | 10 +- Tests/TracingTests/TestTracer.swift | 12 +- Tests/TracingTests/TracedLock.swift | 2 +- Tests/TracingTests/TracedLockTests.swift | 14 +- Tests/TracingTests/TracerTests.swift | 2 +- Tests/TracingTests/TracerTimeTests.swift | 11 +- .../TracingInstrumentationSystemTests.swift | 2 +- 28 files changed, 413 insertions(+), 532 deletions(-) diff --git a/Sources/Instrumentation/Instrument.swift b/Sources/Instrumentation/Instrument.swift index 59ff81c8..76955352 100644 --- a/Sources/Instrumentation/Instrument.swift +++ b/Sources/Instrumentation/Instrument.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/Instrumentation/InstrumentationSystem.swift b/Sources/Instrumentation/InstrumentationSystem.swift index ac72be2f..11e9b7d4 100644 --- a/Sources/Instrumentation/InstrumentationSystem.swift +++ b/Sources/Instrumentation/InstrumentationSystem.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/Instrumentation/Locks.swift b/Sources/Instrumentation/Locks.swift index ae50cb72..606432f7 100644 --- a/Sources/Instrumentation/Locks.swift +++ b/Sources/Instrumentation/Locks.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/Instrumentation/MultiplexInstrument.swift b/Sources/Instrumentation/MultiplexInstrument.swift index fd96c196..21e03c4d 100644 --- a/Sources/Instrumentation/MultiplexInstrument.swift +++ b/Sources/Instrumentation/MultiplexInstrument.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/Instrumentation/NoOpInstrument.swift b/Sources/Instrumentation/NoOpInstrument.swift index 040da89b..f0075660 100644 --- a/Sources/Instrumentation/NoOpInstrument.swift +++ b/Sources/Instrumentation/NoOpInstrument.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/Tracing/InstrumentationSystem+Tracing.swift b/Sources/Tracing/InstrumentationSystem+Tracing.swift index a67710e7..feef86bd 100644 --- a/Sources/Tracing/InstrumentationSystem+Tracing.swift +++ b/Sources/Tracing/InstrumentationSystem+Tracing.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/Tracing/NoOpTracer.swift b/Sources/Tracing/NoOpTracer.swift index 32266f72..1fe2d7a3 100644 --- a/Sources/Tracing/NoOpTracer.swift +++ b/Sources/Tracing/NoOpTracer.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -23,13 +23,13 @@ public struct NoOpTracer: LegacyTracerProtocol { public init() {} - public func startAnySpan(_ operationName: String, - baggage: @autoclosure () -> Baggage, - ofKind kind: SpanKind, - clock: Clock, - function: String, - file fileID: String, - line: UInt) -> any Span + public func startAnySpan(_ operationName: String, + baggage: @autoclosure () -> Baggage, + ofKind kind: SpanKind, + clock: Clock, + function: String, + file fileID: String, + line: UInt) -> any Span { NoOpSpan(baggage: baggage()) } @@ -84,7 +84,7 @@ public struct NoOpTracer: LegacyTracerProtocol { } } - public func end(clock: Clock) { + public func end(clock: Clock) { // ignore } } @@ -92,7 +92,7 @@ public struct NoOpTracer: LegacyTracerProtocol { #if swift(>=5.7.0) extension NoOpTracer: TracerProtocol { - public func startSpan( + public func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, diff --git a/Sources/Tracing/SpanProtocol.swift b/Sources/Tracing/SpanProtocol.swift index bfd76696..81f4ab87 100644 --- a/Sources/Tracing/SpanProtocol.swift +++ b/Sources/Tracing/SpanProtocol.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -12,11 +12,6 @@ // //===----------------------------------------------------------------------===// -#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 @@ -98,10 +93,11 @@ public protocol Span: _SwiftTracingSendableSpan { /// Implementations SHOULD prevent double-emitting by marking a span as ended internally, however it still is a /// programming mistake to rely on this behavior. /// - /// - Parameter time: The `DispatchWallTime` at which the span ended. + /// Parameters: + /// - clock: The clock to use as time source for the start time of the ``Span`` /// /// - SeeAlso: `Span.end()` which automatically uses the "current" time. - func end(clock: Clock) + func end(clock: Clock) } extension Span { @@ -115,12 +111,10 @@ extension Span { /// Implementations SHOULD prevent double-emitting by marking a span as ended internally, however it still is a /// programming mistake to rely on this behavior. /// - /// - Parameter time: The `DispatchWallTime` at which the span ended. - /// - /// - SeeAlso: ``end(at:)`` which allows passing in a specific time, e.g. if the operation was ended and recorded somewhere and we need to post-factum record it. + /// - SeeAlso: ``end(clock:)`` which allows passing in a specific time, e.g. if the operation was ended and recorded somewhere and we need to post-factum record it. /// Generally though prefer using the ``end()`` version of this API in user code and structure your system such that it can be called in the right place and time. public func end() { - self.end(clock: TracerClock()) + self.end(clock: DefaultTracerClock()) } /// Adds a ``SpanLink`` between this `Span` and the given `Span`. @@ -160,15 +154,23 @@ public struct SpanEvent: Equatable { /// - Parameters: /// - name: The human-readable name of this event. /// - attributes: attributes describing this event. Defaults to no attributes. - /// - time: The `DispatchWallTime` at which this event occurred. Defaults to `.now()`. - public init(name: String, - attributes: SpanAttributes = [:], - clock: Clock = TracerClock()) + /// - clock: The clock to use as time source for the start time of the ``Span`` + public init(name: String, + clock: Clock, + attributes: SpanAttributes = [:]) { self.name = name self.attributes = attributes self.time = clock.now.millisSinceEpoch } + + public init(name: String, + attributes: SpanAttributes = [:]) + { + self.name = name + self.attributes = attributes + self.time = DefaultTracerClock.now.millisSinceEpoch + } } extension SpanEvent: ExpressibleByStringLiteral { diff --git a/Sources/Tracing/Tracer.swift b/Sources/Tracing/Tracer.swift index e7c7780f..110bdd36 100644 --- a/Sources/Tracing/Tracer.swift +++ b/Sources/Tracing/Tracer.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -44,14 +44,16 @@ extension Tracer { /// /// - Parameters: /// - operationName: The name of the operation being traced. This may be a handler function, database call, ... + /// - clock: The clock to use as time source for the start time of the ``Span`` /// - baggage: The `Baggage` providing information on where to start the new ``Span``. /// - kind: The ``SpanKind`` of 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. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage - static func startSpan( + static func startSpan( _ operationName: String, + clock: Clock, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, function: String = #function, @@ -60,86 +62,65 @@ extension Tracer { ) -> any Span { // Effectively these end up calling the same method, however // we try to not use the deprecated methods ourselves anyway - #if swift(>=5.7.0) - InstrumentationSystem.tracer.startSpan( - operationName, - clock: TracerClock(), - function: function, - file: fileID, - line: line - ) - #else InstrumentationSystem.legacyTracer.startAnySpan( operationName, + clock: clock, baggage: baggage(), ofKind: kind, - at: { $0.now }, - clock: TracerClock(), function: function, file: fileID, line: line ) - #endif } - /// Start a new ``Span`` using the global bootstrapped tracer reimplementation. - /// - /// The current task-local `Baggage` is picked up and provided to the underlying tracer. - /// It is also possible to pass a specific `baggage` explicitly, in which case attempting - /// to pick up the task-local baggage is prevented. This can be useful when we know that - /// we're about to start a top-level span, or if a span should be started from a different, - /// stored away previously, - /// - /// - Note: Prefer ``withSpan(_:baggage:ofKind:at:function:file:line:operation:)`` to start - /// a span as it automatically takes care of ending the span, and recording errors when thrown. - /// Use `startSpan` iff you need to pass the span manually to a different - /// location in your source code to end it. - /// - /// - Warning: You must `end()` the span when it the measured operation has completed explicitly, - /// otherwise the span object will potentially never be released nor reported. - /// - /// - Parameters: - /// - 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 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. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage - static func startSpan( + static func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line ) -> any Span { // Effectively these end up calling the same method, however // we try to not use the deprecated methods ourselves anyway - #if swift(>=5.7.0) - InstrumentationSystem.tracer.startSpan( + InstrumentationSystem.legacyTracer.startAnySpan( operationName, + clock: DefaultTracerClock(), baggage: baggage(), ofKind: kind, - clock: clock, function: function, file: fileID, line: line ) - #else - InstrumentationSystem.legacyTracer.startAnySpan( + } + + #if swift(>=5.7.0) + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage + static func startSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + clock: some TracerClock = DefaultTracerClock(), + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line + ) -> any Span { + // Effectively these end up calling the same method, however + // we try to not use the deprecated methods ourselves anyway + InstrumentationSystem.tracer.startAnySpan( operationName, + clock: clock, baggage: baggage(), ofKind: kind, - clock: clock, function: function, file: fileID, line: line ) - #endif } + #endif + + // ==== withSpan + sync --------------------------------------------------- /// Start a new ``Span`` and automatically end when the `operation` completes, /// including recording the `error` in case the operation throws. @@ -157,7 +138,7 @@ extension Tracer { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. @@ -165,8 +146,9 @@ extension Tracer { /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage - public static func withSpan( + public static func withSpan( _ operationName: String, + clock: Clock, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, function: String = #function, @@ -174,20 +156,10 @@ extension Tracer { line: UInt = #line, _ operation: (any Span) throws -> T ) rethrows -> T { - #if swift(>=5.7.0) - try InstrumentationSystem.legacyTracer.withAnySpan( - operationName, - ofKind: kind, - clock: TracerClock(), - function: function, - file: fileID, - line: line - ) { anySpan in - try operation(anySpan) - } - #else try InstrumentationSystem.legacyTracer.withAnySpan( operationName, + clock: DefaultTracerClock(), + baggage: baggage(), ofKind: kind, function: function, file: fileID, @@ -195,44 +167,57 @@ extension Tracer { ) { anySpan in try operation(anySpan) } - #endif } @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage - public static func withSpan( + public static func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, _ operation: (any Span) throws -> T ) rethrows -> T { - #if swift(>=5.7.0) try InstrumentationSystem.legacyTracer.withAnySpan( operationName, + clock: DefaultTracerClock(), + baggage: baggage(), ofKind: kind, - clock: clock, function: function, file: fileID, line: line ) { anySpan in try operation(anySpan) } - #else + } + + #if swift(>=5.7.0) + public static func withSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + clock: some TracerClock = DefaultTracerClock(), + function: String = #function, + file fileID: String = #fileID, + line: UInt = #line, + _ operation: (any Span) throws -> T + ) rethrows -> T { try InstrumentationSystem.legacyTracer.withAnySpan( operationName, - ofKind: kind, clock: clock, + baggage: baggage(), + ofKind: kind, function: function, file: fileID, line: line ) { anySpan in try operation(anySpan) } - #endif } + #endif + + // ==== withSpan + async -------------------------------------------------- /// Start a new ``Span`` and automatically end when the `operation` completes, /// including recording the `error` in case the operation throws. @@ -257,20 +242,22 @@ extension Tracer { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) - public static func withSpan( + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage + public static func withSpan( _ operationName: String, + clock: Clock, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, function: String = #function, file fileID: String = #fileID, line: UInt = #line, - @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T + _ operation: (any Span) async throws -> T ) async rethrows -> T { try await InstrumentationSystem.legacyTracer.withAnySpan( operationName, + clock: DefaultTracerClock(), baggage: baggage(), ofKind: kind, - clock: TracerClock(), function: function, file: fileID, line: line @@ -279,21 +266,45 @@ extension Tracer { } } - public static func withSpan( + @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage + public static func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, - @_inheritActorContext @_implicitSelfCapture _ operation: (any Span) async throws -> T + _ operation: (any Span) async throws -> T ) async rethrows -> T { try await InstrumentationSystem.legacyTracer.withAnySpan( operationName, + clock: DefaultTracerClock(), baggage: baggage(), ofKind: kind, + function: function, + file: fileID, + line: line + ) { anySpan in + try await operation(anySpan) + } + } + + #if swift(>=5.7.0) + public static func withSpan( + _ operationName: String, + baggage: @autoclosure () -> Baggage = .current ?? .topLevel, + ofKind kind: SpanKind = .internal, + clock: some TracerClock = DefaultTracerClock(), + 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, clock: clock, + baggage: baggage(), + ofKind: kind, function: function, file: fileID, line: line @@ -301,4 +312,5 @@ extension Tracer { try await operation(anySpan) } } + #endif } diff --git a/Sources/Tracing/TracerProtocol+Legacy.swift b/Sources/Tracing/TracerProtocol+Legacy.swift index 389fad85..212f5916 100644 --- a/Sources/Tracing/TracerProtocol+Legacy.swift +++ b/Sources/Tracing/TracerProtocol+Legacy.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -43,11 +43,11 @@ public protocol LegacyTracerProtocol: InstrumentProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. - func startAnySpan( + func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, @@ -71,6 +71,8 @@ public protocol LegacyTracerProtocol: InstrumentProtocol { @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage extension LegacyTracerProtocol { + // ==== startSpan --------------------------------------------------------- + /// Start a new span returning an existential ``Span`` reference. /// /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` @@ -96,15 +98,15 @@ extension LegacyTracerProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. - public func startAnySpan( + public func startAnySpan( _ operationName: String, + clock: Clock, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -132,51 +134,20 @@ extension LegacyTracerProtocol { operationName, baggage: baggage(), ofKind: kind, - clock: TracerClock(), + clock: DefaultTracerClock(), function: function, file: fileID, line: line ) } - /// Start a new ``Span`` and automatically end when the `operation` completes, - /// including recording the `error` in case the operation throws. - /// - /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` - /// is recommended instead. - /// - /// The current task-local `Baggage` is picked up and provided to the underlying tracer. - /// It is also possible to pass a specific `baggage` explicitly, in which case attempting - /// to pick up the task-local baggage is prevented. This can be useful when we know that - /// we're about to start a top-level span, or if a span should be started from a different, - /// stored away previously, - /// - /// - Note: Legacy API, prefer using ``startSpan(_:baggage:ofKind:at: - /// - /// - Note: Prefer ``withSpan(_:baggage:ofKind:at:function:file:line:operation:)`` to start - /// a span as it automatically takes care of ending the span, and recording errors when thrown. - /// Use `startSpan` iff you need to pass the span manually to a different - /// location in your source code to end it. - /// - /// - Warning: You must `end()` the span when it the measured operation has completed explicitly, - /// otherwise the span object will potentially never be released nor reported. - /// - /// - Parameters: - /// - 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 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. - /// - operation: The operation that this span should be measuring - /// - Returns: the value returned by `operation` - /// - Throws: the error the `operation` has thrown (if any) - public func withAnySpan( + // ==== withAnySpan + sync ------------------------------------------------ + + public func withAnySpan( _ operationName: String, + clock: Clock, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -213,9 +184,9 @@ extension LegacyTracerProtocol { ) rethrows -> T { try self.withAnySpan( operationName, + clock: DefaultTracerClock(), baggage: baggage(), ofKind: kind, - clock: TracerClock(), function: function, file: fileID, line: line, @@ -223,44 +194,13 @@ extension LegacyTracerProtocol { ) } - /// Start a new ``Span`` and automatically end when the `operation` completes, - /// including recording the `error` in case the operation throws. - /// - /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` - /// is recommended instead. - /// - /// The current task-local `Baggage` is picked up and provided to the underlying tracer. - /// It is also possible to pass a specific `baggage` explicitly, in which case attempting - /// to pick up the task-local baggage is prevented. This can be useful when we know that - /// we're about to start a top-level span, or if a span should be started from a different, - /// stored away previously, - /// - /// - Note: Legacy API, prefer using ``startSpan(_:baggage:ofKind:at: - /// - /// - Note: Prefer ``withSpan(_:baggage:ofKind:at:function:file:line:operation:)`` to start - /// a span as it automatically takes care of ending the span, and recording errors when thrown. - /// Use `startSpan` iff you need to pass the span manually to a different - /// location in your source code to end it. - /// - /// - Warning: You must `end()` the span when it the measured operation has completed explicitly, - /// otherwise the span object will potentially never be released nor reported. - /// - /// - Parameters: - /// - 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 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. - /// - operation: The operation that this span should be measuring - /// - Returns: the value returned by `operation` - /// - Throws: the error the `operation` has thrown (if any) - public func withAnySpan( + // ==== withAnySpan async ------------------------------------------------- + + public func withAnySpan( _ operationName: String, + clock: Clock, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -268,9 +208,9 @@ extension LegacyTracerProtocol { ) async rethrows -> T { let span = self.startAnySpan( operationName, + clock: clock, baggage: baggage(), ofKind: kind, - clock: clock, function: function, file: fileID, line: line @@ -297,9 +237,9 @@ extension LegacyTracerProtocol { ) async rethrows -> T { let span = self.startAnySpan( operationName, + clock: DefaultTracerClock(), baggage: baggage(), ofKind: kind, - clock: TracerClock(), function: function, file: fileID, line: line @@ -314,42 +254,11 @@ extension LegacyTracerProtocol { throw error // rethrow } } - -// public func withAnySpan( -// _ operationName: String, -// baggage: @autoclosure () -> Baggage = .current ?? .topLevel, -// ofKind kind: SpanKind = .internal, -// clock: Clock = TracerClock(), -// function: String = #function, -// file fileID: String = #fileID, -// line: UInt = #line, -// _ operation: (any Span) async throws -> T -// ) async rethrows -> T { -// let span = self.startAnySpan( -// operationName, -// baggage: baggage(), -// ofKind: kind, -// clock: clock, -// function: function, -// file: fileID, -// line: line -// ) -// defer { span.end() } -// do { -// return try await Baggage.$current.withValue(span.baggage) { -// try await operation(span) -// } -// } catch { -// span.recordError(error) -// throw error // rethrow -// } -// } } #if swift(>=5.7.0) // Provide compatibility shims of the `...AnySpan` APIs to the 5.7 requiring `TracerProtocol`. -// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) extension TracerProtocol { /// Start a new span returning an existential ``Span`` reference. /// @@ -376,66 +285,18 @@ extension TracerProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. public func startAnySpan( _ operationName: String, + clock: some TracerClock = DefaultTracerClock(), baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, function: String = #function, file fileID: String = #fileID, line: UInt = #line - ) -> any Span { - self.startAnySpan( - operationName, - baggage: baggage(), - ofKind: kind, - clock: TracerClock(), - function: function, - file: fileID, - line: line - ) - } - - /// Start a new span returning an existential ``Span`` reference. - /// - /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` - /// is recommended instead. - /// - /// The current task-local `Baggage` is picked up and provided to the underlying tracer. - /// It is also possible to pass a specific `baggage` explicitly, in which case attempting - /// to pick up the task-local baggage is prevented. This can be useful when we know that - /// we're about to start a top-level span, or if a span should be started from a different, - /// stored away previously, - /// - /// - Note: Legacy API, prefer using ``startSpan(_:baggage:ofKind:at: - /// - /// - Note: Prefer ``withSpan(_:baggage:ofKind:at:function:file:line:operation:)`` to start - /// a span as it automatically takes care of ending the span, and recording errors when thrown. - /// Use `startSpan` iff you need to pass the span manually to a different - /// location in your source code to end it. - /// - /// - Warning: You must `end()` the span when it the measured operation has completed explicitly, - /// otherwise the span object will potentially never be released nor reported. - /// - /// - Parameters: - /// - 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 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. - public func startAnySpan( - _ operationName: String, - baggage: @autoclosure () -> Baggage = .current ?? .topLevel, - ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), - function: String = #function, - file fileID: String = #fileID, - line: UInt = #line ) -> any Span { self.startSpan( operationName, @@ -474,18 +335,18 @@ extension TracerProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) - public func withAnySpan( + public func withAnySpan( _ operationName: String, + clock: some TracerClock = DefaultTracerClock(), baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -530,18 +391,18 @@ extension TracerProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) - public func withAnySpan( + public func withAnySpan( _ operationName: String, + clock: some TracerClock = DefaultTracerClock(), baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, diff --git a/Sources/Tracing/TracerProtocol.swift b/Sources/Tracing/TracerProtocol.swift index 2e482fb5..61f8ac4a 100644 --- a/Sources/Tracing/TracerProtocol.swift +++ b/Sources/Tracing/TracerProtocol.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -19,6 +19,7 @@ // MARK: Tracer protocol #if swift(>=5.7.0) + /// A tracer capable of creating new trace spans. /// /// A tracer is a special kind of instrument with the added ability to start a ``Span``. @@ -47,11 +48,11 @@ public protocol TracerProtocol: LegacyTracerProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. - func startSpan( + func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, @@ -88,11 +89,11 @@ extension TracerProtocol { /// - 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. - public func startSpan( + public func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), + clock: some TracerClock = DefaultTracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line @@ -136,11 +137,11 @@ extension TracerProtocol { /// - operation: The operation that this span should be measuring /// - Returns: the value returned by `operation` /// - Throws: the error the `operation` has thrown (if any) - public func withSpan( + public func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), + clock: some TracerClock = DefaultTracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, @@ -179,7 +180,7 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - clock: TracerClock(), + clock: DefaultTracerClock(), function: function, file: fileID, line: line @@ -211,7 +212,7 @@ extension TracerProtocol { /// - 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 time at which to start the new ``Span``. + /// - clock: The clock to use as time source for the start time of the ``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. @@ -231,7 +232,7 @@ extension TracerProtocol { operationName, baggage: baggage(), ofKind: kind, - clock: TracerClock(), + clock: DefaultTracerClock(), function: function, file: fileID, line: line @@ -247,11 +248,11 @@ extension TracerProtocol { } } - public func withSpan( + public func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, ofKind kind: SpanKind = .internal, - clock: Clock = TracerClock(), + clock: some TracerClock = DefaultTracerClock(), function: String = #function, file fileID: String = #fileID, line: UInt = #line, diff --git a/Sources/Tracing/TracingTime.swift b/Sources/Tracing/TracingTime.swift index 2ab8399d..353e139b 100644 --- a/Sources/Tracing/TracingTime.swift +++ b/Sources/Tracing/TracingTime.swift @@ -2,7 +2,7 @@ // // 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 +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -52,19 +52,19 @@ public protocol TracerInstantProtocol: SwiftDistributedTracingInstantProtocol { /// It does not have to allow sleeping, nor is it interchangeable with other notions of clocks (e.g. such as monotonic time etc). /// /// If the standard library, or foundation, or someone else were to implement an UTCClock or UNIXTimestampClock, -/// they can be made to conform to `TracerClockProtocol`. +/// they can be made to conform to `TracerClock`. /// /// The primary purpose of this clock protocol is to enable mocking the "now" time when starting and ending spans, /// especially when the system is already using some notion of simulated or mocked time, such that traces are /// expressed using the same notion of time. -public protocol TracerClockProtocol { +public protocol TracerClock { associatedtype Instant: TracerInstantProtocol var now: Self.Instant { get } } /// A basic "timestamp clock" implementation that is able to five the current time as an unix timestamp. -public struct TracerClock: TracerClockProtocol { +public struct DefaultTracerClock: TracerClock { public typealias Instant = Timestamp internal typealias TimeInterval = Double @@ -94,7 +94,7 @@ public struct TracerClock: TracerClockProtocol { } public static var now: Self.Instant { - TracerClock().now + DefaultTracerClock().now } public var now: Self.Instant { diff --git a/Sources/_TracingBenchmarkTools/ArgParser.swift b/Sources/_TracingBenchmarkTools/ArgParser.swift index 16ddb61c..518defb6 100644 --- a/Sources/_TracingBenchmarkTools/ArgParser.swift +++ b/Sources/_TracingBenchmarkTools/ArgParser.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/_TracingBenchmarkTools/BenchmarkCategory.swift b/Sources/_TracingBenchmarkTools/BenchmarkCategory.swift index 126cc161..174fa28b 100644 --- a/Sources/_TracingBenchmarkTools/BenchmarkCategory.swift +++ b/Sources/_TracingBenchmarkTools/BenchmarkCategory.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/_TracingBenchmarkTools/BenchmarkTools.swift b/Sources/_TracingBenchmarkTools/BenchmarkTools.swift index e48793d1..1a906eef 100644 --- a/Sources/_TracingBenchmarkTools/BenchmarkTools.swift +++ b/Sources/_TracingBenchmarkTools/BenchmarkTools.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/_TracingBenchmarkTools/DriverUtils.swift b/Sources/_TracingBenchmarkTools/DriverUtils.swift index 5968c0c3..8c333663 100644 --- a/Sources/_TracingBenchmarkTools/DriverUtils.swift +++ b/Sources/_TracingBenchmarkTools/DriverUtils.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift b/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift index 9b09270f..1f1faf6a 100644 --- a/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift +++ b/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift @@ -1,156 +1,156 @@ -////===----------------------------------------------------------------------===// -//// -//// This source file is part of the Swift Distributed Tracing open source project -//// -//// Copyright (c) 2020-2021 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 -//// -////===----------------------------------------------------------------------===// -// -// import _TracingBenchmarkTools -// import Tracing -// -// public let SpanAttributesDSLBenchmarks: [BenchmarkInfo] = [ -// BenchmarkInfo( -// name: "SpanAttributesDSLBenchmarks.000_bench_empty", -// runFunction: { _ in try! bench_empty(times: 100) }, -// tags: [], -// setUpFunction: { setUp() }, -// tearDownFunction: tearDown -// ), -// BenchmarkInfo( -// name: "SpanAttributesDSLBenchmarks.001_bench_makeSpan", -// runFunction: { _ in try! bench_makeSpan(times: 100) }, -// tags: [], -// setUpFunction: { setUp() }, -// tearDownFunction: tearDown -// ), -// BenchmarkInfo( -// name: "SpanAttributesDSLBenchmarks.002_bench_startSpan_end", -// runFunction: { _ in try! bench_makeSpan(times: 100) }, -// tags: [], -// setUpFunction: { setUp() }, -// tearDownFunction: tearDown -// ), -// -// BenchmarkInfo( -// name: "SpanAttributesDSLBenchmarks.00_bench_set_String_raw", -// runFunction: { _ in try! bench_set_String_raw(times: 100) }, -// tags: [], -// setUpFunction: { setUp() }, -// tearDownFunction: tearDown -// ), -// BenchmarkInfo( -// name: "SpanAttributesDSLBenchmarks.01_bench_set_String_dsl", -// runFunction: { _ in try! bench_set_String_dsl(times: 100) }, -// tags: [], -// setUpFunction: { setUp() }, -// tearDownFunction: tearDown -// ), -// -// BenchmarkInfo( -// name: "SpanAttributesDSLBenchmarks.02_bench_set_Int_raw", -// runFunction: { _ in try! bench_set_String_raw(times: 100) }, -// tags: [], -// setUpFunction: { setUp() }, -// tearDownFunction: tearDown -// ), -// BenchmarkInfo( -// name: "SpanAttributesDSLBenchmarks.03_bench_set_Int_dsl", -// runFunction: { _ in try! bench_set_String_dsl(times: 100) }, -// tags: [], -// setUpFunction: { setUp() }, -// tearDownFunction: tearDown -// ), -// ] -// -// private var span: (any Span)! -// -// private func setUp() { -// span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) -// } -// -// private func tearDown() { -// span = nil -// } -// -//// ==== ---------------------------------------------------------------------------------------------------------------- -//// MARK: make span -// -// func bench_empty(times: Int) throws {} -// -// func bench_makeSpan(times: Int) throws { -// for _ in 0 ..< times { -// let span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) -// _ = span -// } -// } -// -// func bench_startSpan_end(times: Int) throws { -// for _ in 0 ..< times { -// let span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) -// span.end() -// } -// } -// -//// ==== ---------------------------------------------------------------------------------------------------------------- -//// MARK: set String -// -// func bench_set_String_raw(times: Int) throws { -// for _ in 0 ..< times { -// span.attributes["http.method"] = "POST" -// } -// } -// -// func bench_set_String_dsl(times: Int) throws { -// for _ in 0 ..< times { -// span.attributes.http.method = "POST" -// } -// } -// -//// ==== ---------------------------------------------------------------------------------------------------------------- -//// MARK: set Int -// -// func bench_set_Int_raw(times: Int) throws { -// for _ in 0 ..< times { -// span.attributes["http.status_code"] = 200 -// } -// } -// -// func bench_set_Int_dsl(times: Int) throws { -// for _ in 0 ..< times { -// span.attributes.http.statusCode = 200 -// } -// } -// -// extension SpanAttributes { -// var http: HTTPAttributes { -// get { -// .init(attributes: self) -// } -// set { -// self = newValue.attributes -// } -// } -// } -// -// @dynamicMemberLookup -// struct HTTPAttributes: SpanAttributeNamespace { -// var attributes: SpanAttributes -// -// init(attributes: SpanAttributes) { -// self.attributes = attributes -// } -// -// struct NestedSpanAttributes: NestedSpanAttributesProtocol { -// init() {} -// -// var method: Key { "http.method" } -// var statusCode: Key { "http.status_code" } -// } -// } +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Distributed Tracing open source project +// +// Copyright (c) 2020-2023 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 +// +//===----------------------------------------------------------------------===// + +import _TracingBenchmarkTools +import Tracing + +public let SpanAttributesDSLBenchmarks: [BenchmarkInfo] = [ + BenchmarkInfo( + name: "SpanAttributesDSLBenchmarks.000_bench_empty", + runFunction: { _ in try! bench_empty(times: 100) }, + tags: [], + setUpFunction: { setUp() }, + tearDownFunction: tearDown + ), + BenchmarkInfo( + name: "SpanAttributesDSLBenchmarks.001_bench_makeSpan", + runFunction: { _ in try! bench_makeSpan(times: 100) }, + tags: [], + setUpFunction: { setUp() }, + tearDownFunction: tearDown + ), + BenchmarkInfo( + name: "SpanAttributesDSLBenchmarks.002_bench_startSpan_end", + runFunction: { _ in try! bench_makeSpan(times: 100) }, + tags: [], + setUpFunction: { setUp() }, + tearDownFunction: tearDown + ), + + BenchmarkInfo( + name: "SpanAttributesDSLBenchmarks.00_bench_set_String_raw", + runFunction: { _ in try! bench_set_String_raw(times: 100) }, + tags: [], + setUpFunction: { setUp() }, + tearDownFunction: tearDown + ), + BenchmarkInfo( + name: "SpanAttributesDSLBenchmarks.01_bench_set_String_dsl", + runFunction: { _ in try! bench_set_String_dsl(times: 100) }, + tags: [], + setUpFunction: { setUp() }, + tearDownFunction: tearDown + ), + + BenchmarkInfo( + name: "SpanAttributesDSLBenchmarks.02_bench_set_Int_raw", + runFunction: { _ in try! bench_set_String_raw(times: 100) }, + tags: [], + setUpFunction: { setUp() }, + tearDownFunction: tearDown + ), + BenchmarkInfo( + name: "SpanAttributesDSLBenchmarks.03_bench_set_Int_dsl", + runFunction: { _ in try! bench_set_String_dsl(times: 100) }, + tags: [], + setUpFunction: { setUp() }, + tearDownFunction: tearDown + ), +] + +private var span: (any Span)! + +private func setUp() { + span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) +} + +private func tearDown() { + span = nil +} + +// ==== ---------------------------------------------------------------------------------------------------------------- +// MARK: make span + +func bench_empty(times: Int) throws {} + +func bench_makeSpan(times: Int) throws { + for _ in 0 ..< times { + let span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) + _ = span + } +} + +func bench_startSpan_end(times: Int) throws { + for _ in 0 ..< times { + let span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) + span.end() + } +} + +// ==== ---------------------------------------------------------------------------------------------------------------- +// MARK: set String + +func bench_set_String_raw(times: Int) throws { + for _ in 0 ..< times { + span.attributes["http.method"] = "POST" + } +} + +func bench_set_String_dsl(times: Int) throws { + for _ in 0 ..< times { + span.attributes.http.method = "POST" + } +} + +// ==== ---------------------------------------------------------------------------------------------------------------- +// MARK: set Int + +func bench_set_Int_raw(times: Int) throws { + for _ in 0 ..< times { + span.attributes["http.status_code"] = 200 + } +} + +func bench_set_Int_dsl(times: Int) throws { + for _ in 0 ..< times { + span.attributes.http.statusCode = 200 + } +} + +extension SpanAttributes { + var http: HTTPAttributes { + get { + .init(attributes: self) + } + set { + self = newValue.attributes + } + } +} + +@dynamicMemberLookup +struct HTTPAttributes: SpanAttributeNamespace { + var attributes: SpanAttributes + + init(attributes: SpanAttributes) { + self.attributes = attributes + } + + struct NestedSpanAttributes: NestedSpanAttributesProtocol { + init() {} + + var method: Key { "http.method" } + var statusCode: Key { "http.status_code" } + } +} diff --git a/Sources/_TracingBenchmarks/main.swift b/Sources/_TracingBenchmarks/main.swift index 82c37822..6613a37e 100644 --- a/Sources/_TracingBenchmarks/main.swift +++ b/Sources/_TracingBenchmarks/main.swift @@ -1,42 +1,42 @@ -////===----------------------------------------------------------------------===// -//// -//// This source file is part of the Swift Distributed Tracing open source project -//// -//// Copyright (c) 2020-2021 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 -//// -////===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // -// import _TracingBenchmarkTools +// This source file is part of the Swift Distributed Tracing open source project // -// assert({ -// print("===========================================================================") -// print("= !! YOU ARE RUNNING BENCHMARKS IN DEBUG MODE !! =") -// print("= When running on the command line, use: `swift run -c release` =") -// print("===========================================================================") -// return true -// }()) +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project +// authors +// Licensed under Apache License v2.0 // -// @inline(__always) -// private func registerBenchmark(_ bench: BenchmarkInfo) { -// registeredBenchmarks.append(bench) -// } +// See LICENSE.txt for license information // -// @inline(__always) -// private func registerBenchmark(_ benches: [BenchmarkInfo]) { -// benches.forEach(registerBenchmark) -// } +// SPDX-License-Identifier: Apache-2.0 // -// @inline(__always) -// private func registerBenchmark(_ name: String, _ function: @escaping (Int) -> Void, _ tags: [BenchmarkCategory]) { -// registerBenchmark(BenchmarkInfo(name: name, runFunction: function, tags: tags)) -// } -// -// registerBenchmark(SpanAttributesDSLBenchmarks) -// -// main() +//===----------------------------------------------------------------------===// + +import _TracingBenchmarkTools + +assert({ + print("===========================================================================") + print("= !! YOU ARE RUNNING BENCHMARKS IN DEBUG MODE !! =") + print("= When running on the command line, use: `swift run -c release` =") + print("===========================================================================") + return true +}()) + +@inline(__always) +private func registerBenchmark(_ bench: BenchmarkInfo) { + registeredBenchmarks.append(bench) +} + +@inline(__always) +private func registerBenchmark(_ benches: [BenchmarkInfo]) { + benches.forEach(registerBenchmark) +} + +@inline(__always) +private func registerBenchmark(_ name: String, _ function: @escaping (Int) -> Void, _ tags: [BenchmarkCategory]) { + registerBenchmark(BenchmarkInfo(name: name, runFunction: function, tags: tags)) +} + +registerBenchmark(SpanAttributesDSLBenchmarks) + +main() diff --git a/Tests/InstrumentationTests/InstrumentTests.swift b/Tests/InstrumentationTests/InstrumentTests.swift index cada7ed7..f33e8b9e 100644 --- a/Tests/InstrumentationTests/InstrumentTests.swift +++ b/Tests/InstrumentationTests/InstrumentTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Tests/InstrumentationTests/InstrumentationSystemTests.swift b/Tests/InstrumentationTests/InstrumentationSystemTests.swift index 5f0a2c86..efd2d4c9 100644 --- a/Tests/InstrumentationTests/InstrumentationSystemTests.swift +++ b/Tests/InstrumentationTests/InstrumentationSystemTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Tests/TracingTests/DynamicTracepointTracerTests.swift b/Tests/TracingTests/DynamicTracepointTracerTests.swift index 1ead8237..814eb0ba 100644 --- a/Tests/TracingTests/DynamicTracepointTracerTests.swift +++ b/Tests/TracingTests/DynamicTracepointTracerTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -165,7 +165,7 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { var onEndSpan: (any Span) -> Void = { _ in } - func startAnySpan( + func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, @@ -270,7 +270,7 @@ extension DynamicTracepointTestTracer { static func notRecording(file fileID: String, line: UInt) -> TracepointSpan { let span = TracepointSpan( operationName: "", - startTime: TracerClock().now, + startTime: DefaultTracerClock().now, baggage: .topLevel, kind: .internal, file: fileID, @@ -281,13 +281,13 @@ extension DynamicTracepointTestTracer { return span } - init(operationName: String, - startTime: some TracerInstantProtocol, - baggage: Baggage, - kind: SpanKind, - file fileID: String, - line: UInt, - onEnd: @escaping (TracepointSpan) -> Void) + init(operationName: String, + startTime: Instant, + baggage: Baggage, + kind: SpanKind, + file fileID: String, + line: UInt, + onEnd: @escaping (TracepointSpan) -> Void) { self.operationName = operationName self.startTime = startTime.millisSinceEpoch @@ -322,7 +322,7 @@ extension DynamicTracepointTestTracer { // nothing } - func end(clock: Clock) { + func end(clock: Clock) { self.endTime = clock.now.millisSinceEpoch self.onEnd(self) } @@ -333,13 +333,13 @@ extension DynamicTracepointTestTracer { extension DynamicTracepointTestTracer: TracerProtocol { typealias TracerSpan = TracepointSpan - func startSpan(_ operationName: String, - baggage: @autoclosure () -> Baggage, - ofKind kind: Tracing.SpanKind, - clock: Clock, - function: String, - file fileID: String, - line: UInt) -> TracepointSpan + func startSpan(_ operationName: String, + baggage: @autoclosure () -> Baggage, + ofKind kind: Tracing.SpanKind, + clock: Clock, + function: String, + file fileID: String, + line: UInt) -> TracepointSpan { let tracepoint = TracepointID(function: function, fileID: fileID, line: line) guard self.shouldRecord(tracepoint: tracepoint) else { diff --git a/Tests/TracingTests/SpanTests.swift b/Tests/TracingTests/SpanTests.swift index 59307b54..52cb06f7 100644 --- a/Tests/TracingTests/SpanTests.swift +++ b/Tests/TracingTests/SpanTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -161,7 +161,7 @@ final class SpanTests: XCTestCase { let parent = TestSpan( operationName: "client", - startTime: TracerClock.now, + startTime: DefaultTracerClock.now, baggage: parentBaggage, kind: .client, onEnd: { _ in } @@ -169,7 +169,7 @@ final class SpanTests: XCTestCase { let childBaggage = Baggage.topLevel let child = TestSpan( operationName: "server", - startTime: TracerClock.now, + startTime: DefaultTracerClock.now, baggage: childBaggage, kind: .server, onEnd: { _ in } @@ -195,7 +195,7 @@ final class SpanTests: XCTestCase { let parent = TestSpan( operationName: "client", - startTime: TracerClock.now, + startTime: DefaultTracerClock.now, baggage: parentBaggage, kind: .client, onEnd: { _ in } @@ -203,7 +203,7 @@ final class SpanTests: XCTestCase { let childBaggage = Baggage.topLevel let child = TestSpan( operationName: "server", - startTime: TracerClock.now, + startTime: DefaultTracerClock.now, baggage: childBaggage, kind: .server, onEnd: { _ in } diff --git a/Tests/TracingTests/TestTracer.swift b/Tests/TracingTests/TestTracer.swift index 653be50a..6ca6b1e2 100644 --- a/Tests/TracingTests/TestTracer.swift +++ b/Tests/TracingTests/TestTracer.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -23,7 +23,7 @@ final class TestTracer: LegacyTracerProtocol { private(set) var spans = [TestSpan]() var onEndSpan: (TestSpan) -> Void = { _ in } - func startAnySpan( + func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, @@ -66,7 +66,7 @@ final class TestTracer: LegacyTracerProtocol { #if swift(>=5.7.0) extension TestTracer: TracerProtocol { - func startSpan( + func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, @@ -150,9 +150,9 @@ final class TestSpan: Span { let onEnd: (TestSpan) -> Void - init( + init( operationName: String, - startTime: some TracerInstantProtocol, + startTime: Instant, baggage: Baggage, kind: SpanKind, onEnd: @escaping (TestSpan) -> Void @@ -181,7 +181,7 @@ final class TestSpan: Span { self.recordedErrors.append((error, attributes)) } - func end(clock: Clock = TracerClock()) { + func end(clock: Clock) { self.endTime = clock.now.millisSinceEpoch self.onEnd(self) } diff --git a/Tests/TracingTests/TracedLock.swift b/Tests/TracingTests/TracedLock.swift index 946a2f18..5d0f80fe 100644 --- a/Tests/TracingTests/TracedLock.swift +++ b/Tests/TracingTests/TracedLock.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Tests/TracingTests/TracedLockTests.swift b/Tests/TracingTests/TracedLockTests.swift index 14c4ac53..7f4b52c4 100644 --- a/Tests/TracingTests/TracedLockTests.swift +++ b/Tests/TracingTests/TracedLockTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -60,11 +60,11 @@ enum TaskIDKey: BaggageKey { /// Only intended to be used in single-threaded testing. private final class TracedLockPrintlnTracer: LegacyTracerProtocol { - func startAnySpan( + func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, - clock: Clock = TracerClock(), + clock: Clock, function: String, file fileID: String, line: UInt @@ -124,9 +124,9 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { private(set) var isRecording = false - init( + init( operationName: String, - startTime: some TracerInstantProtocol, + startTime: Instant, kind: SpanKind, baggage: Baggage ) { @@ -153,7 +153,7 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { func recordError(_ error: Error, attributes: SpanAttributes) {} - func end(clock: Clock) { + func end(clock: Clock) { let time = clock.now self.endTimeMillis = time.millisSinceEpoch print(" span [\(self.operationName): \(self.baggage[TaskIDKey.self] ?? "no-name")] @ \(time): end") @@ -163,7 +163,7 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { #if swift(>=5.7.0) extension TracedLockPrintlnTracer: TracerProtocol { - func startSpan( + func startSpan( _ operationName: String, baggage: @autoclosure () -> Baggage, ofKind kind: SpanKind, diff --git a/Tests/TracingTests/TracerTests.swift b/Tests/TracingTests/TracerTests.swift index 15de84e7..5b1f3ce4 100644 --- a/Tests/TracingTests/TracerTests.swift +++ b/Tests/TracingTests/TracerTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // diff --git a/Tests/TracingTests/TracerTimeTests.swift b/Tests/TracingTests/TracerTimeTests.swift index 9eda66d7..70f76ef1 100644 --- a/Tests/TracingTests/TracerTimeTests.swift +++ b/Tests/TracingTests/TracerTimeTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // @@ -24,7 +24,7 @@ final class TracerTimeTests: XCTestCase { } func testTracerTime() { - let t = TracerClock.now + let t = DefaultTracerClock.now let d = Date() XCTAssertEqual( Double(t.millisSinceEpoch) / 1000, // seconds @@ -42,12 +42,17 @@ final class TracerTimeTests: XCTestCase { let mockClock = MockClock() mockClock.setTime(13) + #if swift(>=5.7.0) let span: TestSpan = tracer.startSpan("start", clock: mockClock) XCTAssertEqual(span.startTime, 13) + #else + let span: TestSpan = tracer.startAnySpan("start", clock: mockClock) as! TestSpan + XCTAssertEqual(span.startTime, 13) + #endif } } -final class MockClock: TracerClockProtocol { +final class MockClock: TracerClock { var _now: UInt64 = 0 init() {} diff --git a/Tests/TracingTests/TracingInstrumentationSystemTests.swift b/Tests/TracingTests/TracingInstrumentationSystemTests.swift index b0b9ec2a..d7ed5468 100644 --- a/Tests/TracingTests/TracingInstrumentationSystemTests.swift +++ b/Tests/TracingTests/TracingInstrumentationSystemTests.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift Distributed Tracing open source project // -// Copyright (c) 2020-2021 Apple Inc. and the Swift Distributed Tracing project +// Copyright (c) 2020-2023 Apple Inc. and the Swift Distributed Tracing project // authors // Licensed under Apache License v2.0 // From f2e4d328638a769d78cf3e2499f009fb0e6ed7b8 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 29 Mar 2023 17:26:10 +0900 Subject: [PATCH 7/9] License headers: allow 2023 --- scripts/validate_license_headers.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/validate_license_headers.sh b/scripts/validate_license_headers.sh index 399902f8..ef99c154 100755 --- a/scripts/validate_license_headers.sh +++ b/scripts/validate_license_headers.sh @@ -32,7 +32,7 @@ here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" function replace_acceptable_years() { # this needs to replace all acceptable forms with 'YEARS' - sed -e 's/202[01]-202[12]/YEARS/' -e 's/202[012]/YEARS/' + sed -e 's/202[01]-202[123]/YEARS/' -e 's/202[0123]/YEARS/' } printf "=> Checking license headers\n" From 8b2be6842a7f56e76bcdf78fd76eb154322c571e Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 29 Mar 2023 18:21:50 +0900 Subject: [PATCH 8/9] add documentation --- Sources/Tracing/TracerProtocol+Legacy.swift | 138 ++++++++++++++++++-- Sources/Tracing/TracerProtocol.swift | 46 +++++++ Tests/TracingTests/TracerTests.swift | 15 +++ 3 files changed, 189 insertions(+), 10 deletions(-) diff --git a/Sources/Tracing/TracerProtocol+Legacy.swift b/Sources/Tracing/TracerProtocol+Legacy.swift index 212f5916..407942fb 100644 --- a/Sources/Tracing/TracerProtocol+Legacy.swift +++ b/Sources/Tracing/TracerProtocol+Legacy.swift @@ -20,8 +20,7 @@ import Dispatch public protocol LegacyTracerProtocol: InstrumentProtocol { /// Start a new span returning an existential ``Span`` reference. /// - /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` - /// is recommended instead. + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. /// /// The current task-local `Baggage` is picked up and provided to the underlying tracer. /// It is also possible to pass a specific `baggage` explicitly, in which case attempting @@ -75,8 +74,7 @@ extension LegacyTracerProtocol { /// Start a new span returning an existential ``Span`` reference. /// - /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` - /// is recommended instead. + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. /// /// The current task-local `Baggage` is picked up and provided to the underlying tracer. /// It is also possible to pass a specific `baggage` explicitly, in which case attempting @@ -122,6 +120,34 @@ extension LegacyTracerProtocol { ) } + /// Start a new span returning an existential ``Span`` reference. + /// + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. + /// + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Note: Legacy API, prefer using ``startSpan(_:baggage:ofKind:at: + /// + /// - Note: Prefer ``withSpan(_:baggage:ofKind:at:function:file:line:operation:)`` to start + /// a span as it automatically takes care of ending the span, and recording errors when thrown. + /// Use `startSpan` iff you need to pass the span manually to a different + /// location in your source code to end it. + /// + /// - Warning: You must `end()` the span when it the measured operation has completed explicitly, + /// otherwise the span object will potentially never be released nor reported. + /// + /// - Parameters: + /// - 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``. + /// - 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. public func startAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, @@ -143,6 +169,29 @@ extension LegacyTracerProtocol { // ==== withAnySpan + sync ------------------------------------------------ + /// Start a new ``Span`` and automatically end when the `operation` completes, + /// including recording the `error` in case the operation throws. + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Warning: You MUST NOT ``Span/end()`` the span explicitly, because at the end of the `withSpan` + /// operation closure returning the span will be closed automatically. + /// + /// - Parameters: + /// - 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``. + /// - clock: The clock to use as time source for the start time of the ``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. + /// - operation: The operation that this span should be measuring + /// - Returns: the value returned by `operation` + /// - Throws: the error the `operation` has thrown (if any) public func withAnySpan( _ operationName: String, clock: Clock, @@ -173,6 +222,30 @@ extension LegacyTracerProtocol { } } + /// Start a new ``Span`` and automatically end when the `operation` completes, + /// including recording the `error` in case the operation throws. + /// + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Warning: You MUST NOT ``Span/end()`` the span explicitly, because at the end of the `withSpan` + /// operation closure returning the span will be closed automatically. + /// + /// - Parameters: + /// - 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``. + /// - 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) public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, @@ -196,6 +269,30 @@ extension LegacyTracerProtocol { // ==== withAnySpan async ------------------------------------------------- + /// Start a new ``Span`` and automatically end when the `operation` completes, + /// including recording the `error` in case the operation throws. + /// + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Warning: You MUST NOT ``Span/end()`` the span explicitly, because at the end of the `withSpan` + /// operation closure returning the span will be closed automatically. + /// + /// - Parameters: + /// - 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``. + /// - 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) public func withAnySpan( _ operationName: String, clock: Clock, @@ -226,6 +323,30 @@ extension LegacyTracerProtocol { } } + /// Start a new ``Span`` and automatically end when the `operation` completes, + /// including recording the `error` in case the operation throws. + /// + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Warning: You MUST NOT ``Span/end()`` the span explicitly, because at the end of the `withSpan` + /// operation closure returning the span will be closed automatically. + /// + /// - Parameters: + /// - 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``. + /// - 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) public func withAnySpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, @@ -262,8 +383,7 @@ extension LegacyTracerProtocol { extension TracerProtocol { /// Start a new span returning an existential ``Span`` reference. /// - /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` - /// is recommended instead. + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. /// /// The current task-local `Baggage` is picked up and provided to the underlying tracer. /// It is also possible to pass a specific `baggage` explicitly, in which case attempting @@ -312,8 +432,7 @@ extension TracerProtocol { /// Start a new ``Span`` and automatically end when the `operation` completes, /// including recording the `error` in case the operation throws. /// - /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` - /// is recommended instead. + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. /// /// The current task-local `Baggage` is picked up and provided to the underlying tracer. /// It is also possible to pass a specific `baggage` explicitly, in which case attempting @@ -368,8 +487,7 @@ extension TracerProtocol { /// Start a new ``Span`` and automatically end when the `operation` completes, /// including recording the `error` in case the operation throws. /// - /// This API will be deprecated as soon as Swift 5.9 is released, and the Swift 5.7 requiring `TracerProtocol` - /// is recommended instead. + /// - Warning: This method will be deprecated in favor of `TracerProtocol/withSpan` as soon as this project is able to require Swift 5.7. /// /// The current task-local `Baggage` is picked up and provided to the underlying tracer. /// It is also possible to pass a specific `baggage` explicitly, in which case attempting diff --git a/Sources/Tracing/TracerProtocol.swift b/Sources/Tracing/TracerProtocol.swift index 61f8ac4a..c063a42a 100644 --- a/Sources/Tracing/TracerProtocol.swift +++ b/Sources/Tracing/TracerProtocol.swift @@ -167,6 +167,29 @@ extension TracerProtocol { } } + /// Start a new ``Span`` and automatically end when the `operation` completes, + /// including recording the `error` in case the operation throws. + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Warning: You MUST NOT ``Span/end()`` the span explicitly, because at the end of the `withSpan` + /// operation closure returning the span will be closed automatically. + /// + /// - Parameters: + /// - 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``. + /// - clock: The clock to use as time source for the start time of the ``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. + /// - operation: The operation that this span should be measuring + /// - Returns: the value returned by `operation` + /// - Throws: the error the `operation` has thrown (if any) public func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, @@ -248,6 +271,29 @@ extension TracerProtocol { } } + /// Start a new ``Span`` and automatically end when the `operation` completes, + /// including recording the `error` in case the operation throws. + /// + /// The current task-local `Baggage` is picked up and provided to the underlying tracer. + /// It is also possible to pass a specific `baggage` explicitly, in which case attempting + /// to pick up the task-local baggage is prevented. This can be useful when we know that + /// we're about to start a top-level span, or if a span should be started from a different, + /// stored away previously, + /// + /// - Warning: You MUST NOT ``Span/end()`` the span explicitly, because at the end of the `withSpan` + /// operation closure returning the span will be closed automatically. + /// + /// - Parameters: + /// - 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``. + /// - clock: The clock to use as time source for the start time of the ``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. + /// - operation: The operation that this span should be measuring + /// - Returns: the value returned by `operation` + /// - Throws: the error the `operation` has thrown (if any) public func withSpan( _ operationName: String, baggage: @autoclosure () -> Baggage = .current ?? .topLevel, diff --git a/Tests/TracingTests/TracerTests.swift b/Tests/TracingTests/TracerTests.swift index 5b1f3ce4..f463e4f8 100644 --- a/Tests/TracingTests/TracerTests.swift +++ b/Tests/TracingTests/TracerTests.swift @@ -351,6 +351,21 @@ final class TracerTests: XCTestCase { #endif } + func testWithSpanSignatures() { + let tracer = TestTracer() + let clock = DefaultTracerClock() + + #if swift(>=5.7.0) + tracer.withSpan("") { _ in } + tracer.withSpan("", clock: clock) { _ in } + tracer.withSpan("", baggage: .topLevel) { _ in } + #endif + + tracer.withAnySpan("") { _ in } + tracer.withAnySpan("", clock: clock) { _ in } + tracer.withAnySpan("", baggage: .topLevel) { _ in } + } + #if swift(>=5.7.0) // @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) /// Helper method to execute async operations until we can use async tests (currently incompatible with the generated LinuxMain file). From 9304c0dca1e919bdb3efe95e63349cb7df70c2a4 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 29 Mar 2023 19:40:40 +0900 Subject: [PATCH 9/9] address review comments --- Sources/Tracing/SpanProtocol.swift | 10 +++-- Sources/Tracing/TracingTime.swift | 20 +++++----- Tests/TracingTests/ActorTracingTests.swift | 39 +++++++++++++++++++ .../DynamicTracepointTracerTests.swift | 4 +- Tests/TracingTests/TestTracer.swift | 4 +- Tests/TracingTests/TracedLockTests.swift | 4 +- Tests/TracingTests/TracerTimeTests.swift | 8 ++-- 7 files changed, 64 insertions(+), 25 deletions(-) create mode 100644 Tests/TracingTests/ActorTracingTests.swift diff --git a/Sources/Tracing/SpanProtocol.swift b/Sources/Tracing/SpanProtocol.swift index 81f4ab87..2b3bea10 100644 --- a/Sources/Tracing/SpanProtocol.swift +++ b/Sources/Tracing/SpanProtocol.swift @@ -147,8 +147,10 @@ public struct SpanEvent: Equatable { /// One or more ``SpanAttribute``s with the same restrictions as defined for ``Span`` attributes. public var attributes: SpanAttributes - /// The `DispatchWallTime` at which this event occurred. - public let time: UInt64 + /// The timestamp at which this event occurred. + /// + /// It should be expressed as the number of milliseconds since UNIX Epoch (January 1st 1970). + public let millisecondsSinceEpoch: UInt64 /// Create a new `SpanEvent`. /// - Parameters: @@ -161,7 +163,7 @@ public struct SpanEvent: Equatable { { self.name = name self.attributes = attributes - self.time = clock.now.millisSinceEpoch + self.millisecondsSinceEpoch = clock.now.millisecondsSinceEpoch } public init(name: String, @@ -169,7 +171,7 @@ public struct SpanEvent: Equatable { { self.name = name self.attributes = attributes - self.time = DefaultTracerClock.now.millisSinceEpoch + self.millisecondsSinceEpoch = DefaultTracerClock.now.millisecondsSinceEpoch } } diff --git a/Sources/Tracing/TracingTime.swift b/Sources/Tracing/TracingTime.swift index 353e139b..f3a8c4a4 100644 --- a/Sources/Tracing/TracingTime.swift +++ b/Sources/Tracing/TracingTime.swift @@ -36,14 +36,12 @@ extension SwiftDistributedTracingDurationProtocol { } } -public protocol SwiftDistributedTracingInstantProtocol: Comparable, Hashable, Sendable { - // associatedtype Duration: SwiftDistributedTracingDurationProtocol -} +public protocol SwiftDistributedTracingInstantProtocol: Comparable, Hashable, Sendable {} public protocol TracerInstantProtocol: SwiftDistributedTracingInstantProtocol { /// Representation of this instant as the number of milliseconds since UNIX Epoch (January 1st 1970) @inlinable - var millisSinceEpoch: UInt64 { get } + var millisecondsSinceEpoch: UInt64 { get } } /// A specialized clock protocol for purposes of tracing. @@ -74,22 +72,22 @@ public struct DefaultTracerClock: TracerClock { public struct Timestamp: TracerInstantProtocol { /// Milliseconds since January 1st, 1970, also known as "unix epoch". - public var millisSinceEpoch: UInt64 + public var millisecondsSinceEpoch: UInt64 - internal init(millisSinceEpoch: UInt64) { - self.millisSinceEpoch = millisSinceEpoch + internal init(millisecondsSinceEpoch: UInt64) { + self.millisecondsSinceEpoch = millisecondsSinceEpoch } public static func < (lhs: Instant, rhs: Instant) -> Bool { - lhs.millisSinceEpoch < rhs.millisSinceEpoch + lhs.millisecondsSinceEpoch < rhs.millisecondsSinceEpoch } public static func == (lhs: Instant, rhs: Instant) -> Bool { - lhs.millisSinceEpoch == rhs.millisSinceEpoch + lhs.millisecondsSinceEpoch == rhs.millisecondsSinceEpoch } public func hash(into hasher: inout Hasher) { - self.millisSinceEpoch.hash(into: &hasher) + self.millisecondsSinceEpoch.hash(into: &hasher) } } @@ -106,7 +104,7 @@ public struct DefaultTracerClock: TracerClock { let nowNanos = UInt64(ts.tv_sec) &* 1_000_000_000 &+ UInt64(ts.tv_nsec) let nowMillis = UInt64(nowNanos / 1_000_000) // nanos to millis - return Instant(millisSinceEpoch: nowMillis) + return Instant(millisecondsSinceEpoch: nowMillis) } } diff --git a/Tests/TracingTests/ActorTracingTests.swift b/Tests/TracingTests/ActorTracingTests.swift new file mode 100644 index 00000000..6d6bd7f2 --- /dev/null +++ b/Tests/TracingTests/ActorTracingTests.swift @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Distributed Tracing open source project +// +// Copyright (c) 2020-2023 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 +// +//===----------------------------------------------------------------------===// + +@testable import Instrumentation +import InstrumentationBaggage +import Tracing +import XCTest + +final class ActorTracingTests: XCTestCase { + override class func tearDown() { + super.tearDown() + InstrumentationSystem.bootstrapInternal(nil) + } +} + +func work() async {} + +actor Foo { + var bar = 0 + func foo() async { + var num = 0 + await Tracer.withSpan(#function) { _ in + bar += 1 + await work() + num += 1 + } + } +} diff --git a/Tests/TracingTests/DynamicTracepointTracerTests.swift b/Tests/TracingTests/DynamicTracepointTracerTests.swift index 814eb0ba..cc872b37 100644 --- a/Tests/TracingTests/DynamicTracepointTracerTests.swift +++ b/Tests/TracingTests/DynamicTracepointTracerTests.swift @@ -290,7 +290,7 @@ extension DynamicTracepointTestTracer { onEnd: @escaping (TracepointSpan) -> Void) { self.operationName = operationName - self.startTime = startTime.millisSinceEpoch + self.startTime = startTime.millisecondsSinceEpoch self.baggage = baggage self.onEnd = onEnd self.kind = kind @@ -323,7 +323,7 @@ extension DynamicTracepointTestTracer { } func end(clock: Clock) { - self.endTime = clock.now.millisSinceEpoch + self.endTime = clock.now.millisecondsSinceEpoch self.onEnd(self) } } diff --git a/Tests/TracingTests/TestTracer.swift b/Tests/TracingTests/TestTracer.swift index 6ca6b1e2..eee74e61 100644 --- a/Tests/TracingTests/TestTracer.swift +++ b/Tests/TracingTests/TestTracer.swift @@ -158,7 +158,7 @@ final class TestSpan: Span { onEnd: @escaping (TestSpan) -> Void ) { self.operationName = operationName - self.startTime = startTime.millisSinceEpoch + self.startTime = startTime.millisecondsSinceEpoch self.baggage = baggage self.onEnd = onEnd self.kind = kind @@ -182,7 +182,7 @@ final class TestSpan: Span { } func end(clock: Clock) { - self.endTime = clock.now.millisSinceEpoch + self.endTime = clock.now.millisecondsSinceEpoch self.onEnd(self) } } diff --git a/Tests/TracingTests/TracedLockTests.swift b/Tests/TracingTests/TracedLockTests.swift index 7f4b52c4..9294bf94 100644 --- a/Tests/TracingTests/TracedLockTests.swift +++ b/Tests/TracingTests/TracedLockTests.swift @@ -131,7 +131,7 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { baggage: Baggage ) { self.operationName = operationName - self.startTimeMillis = startTime.millisSinceEpoch + self.startTimeMillis = startTime.millisecondsSinceEpoch self.baggage = baggage self.kind = kind @@ -155,7 +155,7 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { func end(clock: Clock) { let time = clock.now - self.endTimeMillis = time.millisSinceEpoch + self.endTimeMillis = time.millisecondsSinceEpoch print(" span [\(self.operationName): \(self.baggage[TaskIDKey.self] ?? "no-name")] @ \(time): end") } } diff --git a/Tests/TracingTests/TracerTimeTests.swift b/Tests/TracingTests/TracerTimeTests.swift index 70f76ef1..3e2bb9d0 100644 --- a/Tests/TracingTests/TracerTimeTests.swift +++ b/Tests/TracingTests/TracerTimeTests.swift @@ -27,7 +27,7 @@ final class TracerTimeTests: XCTestCase { let t = DefaultTracerClock.now let d = Date() XCTAssertEqual( - Double(t.millisSinceEpoch) / 1000, // seconds + Double(t.millisecondsSinceEpoch) / 1000, // seconds d.timeIntervalSince1970, // seconds accuracy: 10 ) @@ -62,13 +62,13 @@ final class MockClock: TracerClock { } struct Instant: TracerInstantProtocol { - var millisSinceEpoch: UInt64 + var millisecondsSinceEpoch: UInt64 static func < (lhs: MockClock.Instant, rhs: MockClock.Instant) -> Bool { - lhs.millisSinceEpoch < rhs.millisSinceEpoch + lhs.millisecondsSinceEpoch < rhs.millisecondsSinceEpoch } } var now: Instant { - Instant(millisSinceEpoch: self._now) + Instant(millisecondsSinceEpoch: self._now) } }