From a7e66b39f959c1619812eb973503431e3f0d9c1c Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 16 Mar 2023 17:28:27 +0900 Subject: [PATCH 1/3] SpanProtocol -> Span after all Rationale: since passing around any SpanProtocol a lot looked terrible; Also, less breakage in protocol renaming --- Sources/Tracing/NoOpTracer.swift | 6 ++-- Sources/Tracing/SpanProtocol.swift | 10 +++---- Sources/Tracing/Tracer.swift | 12 ++++---- Sources/Tracing/TracerProtocol+Legacy.swift | 30 +++++++++---------- Sources/Tracing/TracerProtocol.swift | 16 +++++----- .../SpanAttributesDSLBenchmark.swift | 2 +- .../DynamicTracepointTracerTests.swift | 8 ++--- Tests/TracingTests/SpanTests.swift | 7 +---- Tests/TracingTests/TestTracer.swift | 4 +-- Tests/TracingTests/TracedLock.swift | 2 +- Tests/TracingTests/TracedLockTests.swift | 4 +-- Tests/TracingTests/TracerTests.swift | 20 ++++++------- 12 files changed, 57 insertions(+), 64 deletions(-) diff --git a/Sources/Tracing/NoOpTracer.swift b/Sources/Tracing/NoOpTracer.swift index 8bfcc03c..5694c89a 100644 --- a/Sources/Tracing/NoOpTracer.swift +++ b/Sources/Tracing/NoOpTracer.swift @@ -18,7 +18,7 @@ import Dispatch /// Tracer that ignores all operations, used when no tracing is required. public struct NoOpTracer: LegacyTracerProtocol { - public typealias Span = NoOpSpan + public typealias TracerSpan = NoOpSpan public init() {} @@ -28,7 +28,7 @@ public struct NoOpTracer: LegacyTracerProtocol { at time: DispatchWallTime, function: String, file fileID: String, - line: UInt) -> any SpanProtocol + line: UInt) -> any Span { NoOpSpan(baggage: baggage()) } @@ -47,7 +47,7 @@ public struct NoOpTracer: LegacyTracerProtocol { // no-op } - public final class NoOpSpan: SpanProtocol { + public final class NoOpSpan: Span { public let baggage: Baggage public var isRecording: Bool { false diff --git a/Sources/Tracing/SpanProtocol.swift b/Sources/Tracing/SpanProtocol.swift index 2c44def6..e650f51a 100644 --- a/Sources/Tracing/SpanProtocol.swift +++ b/Sources/Tracing/SpanProtocol.swift @@ -26,7 +26,7 @@ import struct Dispatch.DispatchWallTime /// Creating a `Span` is delegated to a ``Tracer`` and end users should never create them directly. /// /// - SeeAlso: For more details refer to the [OpenTelemetry Specification: Span](https://github.com/open-telemetry/opentelemetry-specification/blob/v0.7.0/specification/trace/api.md#span) which this type is compatible with. -public protocol SpanProtocol: AnyObject, _SwiftTracingSendableSpan { +public protocol Span: AnyObject, _SwiftTracingSendableSpan { /// The read-only `Baggage` of this `Span`, set when starting this `Span`. var baggage: Baggage { get } @@ -91,7 +91,7 @@ public protocol SpanProtocol: AnyObject, _SwiftTracingSendableSpan { func end(at time: DispatchWallTime) } -extension SpanProtocol { +extension Span { /// End this `Span` at the current time. /// /// ### Rules about ending Spans @@ -114,12 +114,12 @@ extension SpanProtocol { /// /// - Parameter other: The `Span` to link to. /// - Parameter attributes: The ``SpanAttributes`` describing this link. Defaults to no attributes. - public func addLink(_ other: SpanProtocol, attributes: SpanAttributes = [:]) { + public func addLink(_ other: Span, attributes: SpanAttributes = [:]) { self.addLink(SpanLink(baggage: other.baggage, attributes: attributes)) } } -extension SpanProtocol { +extension Span { /// Record a failure described by the given error. /// /// - Parameters: @@ -176,7 +176,6 @@ public struct SpanAttributeKey: Hashable, ExpressibleByStringLiteral where T: } } -#if swift(>=5.2) @dynamicMemberLookup public protocol SpanAttributeNamespace { /// Type that contains the nested attributes, e.g. HTTPAttributes which would contain `statusCode` and similar vars. @@ -247,7 +246,6 @@ extension SpanAttributeNamespace { SpanAttribute.int(0)[keyPath: dynamicMember] } } -#endif /// The value of an attribute used to describe a ``Span`` or ``SpanEvent``. /// diff --git a/Sources/Tracing/Tracer.swift b/Sources/Tracing/Tracer.swift index b675e677..2138a96c 100644 --- a/Sources/Tracing/Tracer.swift +++ b/Sources/Tracing/Tracer.swift @@ -58,7 +58,7 @@ extension Tracer { function: String = #function, file fileID: String = #fileID, line: UInt = #line - ) -> any SpanProtocol { + ) -> 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) @@ -90,7 +90,7 @@ extension Tracer { /// 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 ``SpanProtocol/end()`` the span explicitly, because at the end of the `withSpan` + /// - 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: @@ -111,7 +111,7 @@ extension Tracer { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any SpanProtocol) throws -> T + _ operation: (any Span) throws -> T ) rethrows -> T { #if swift(>=5.7.0) try InstrumentationSystem.legacyTracer.withAnySpan( @@ -145,7 +145,7 @@ extension Tracer { /// 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 ``SpanProtocol/end()`` the span explicitly, because at the end of the `withSpan` + /// - 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: @@ -170,7 +170,7 @@ extension Tracer { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any SpanProtocol) async throws -> T + _ operation: (any Span) async throws -> T ) async rethrows -> T { try await InstrumentationSystem.legacyTracer.withAnySpan( operationName, @@ -194,7 +194,7 @@ extension Tracer { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any SpanProtocol) async throws -> T + _ 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 a2a5ad05..07e3da69 100644 --- a/Sources/Tracing/TracerProtocol+Legacy.swift +++ b/Sources/Tracing/TracerProtocol+Legacy.swift @@ -18,7 +18,7 @@ import Dispatch @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage public protocol LegacyTracerProtocol: InstrumentProtocol { - /// Start a new span returning an existential ``SpanProtocol`` reference. + /// 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. @@ -55,7 +55,7 @@ public protocol LegacyTracerProtocol: InstrumentProtocol { function: String, file fileID: String, line: UInt - ) -> any SpanProtocol + ) -> any Span /// Export all ended spans to the configured backend that have not yet been exported. /// @@ -71,7 +71,7 @@ public protocol LegacyTracerProtocol: InstrumentProtocol { @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage extension LegacyTracerProtocol { - /// Start a new span returning an existential ``SpanProtocol`` reference. + /// 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. @@ -108,7 +108,7 @@ extension LegacyTracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line - ) -> any SpanProtocol { + ) -> any Span { self.startAnySpan( operationName, baggage: baggage(), @@ -120,7 +120,7 @@ extension LegacyTracerProtocol { ) } - /// Start a new ``SpanProtocol`` and automatically end when the `operation` completes, + /// 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` @@ -161,7 +161,7 @@ extension LegacyTracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any SpanProtocol) throws -> T + _ operation: (any Span) throws -> T ) rethrows -> T { let span = self.startAnySpan(operationName, baggage: baggage(), ofKind: kind, at: time, function: function, file: fileID, line: line) defer { span.end() } @@ -175,7 +175,7 @@ extension LegacyTracerProtocol { } } - /// Start a new ``SpanProtocol`` and automatically end when the `operation` completes, + /// 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` @@ -216,7 +216,7 @@ extension LegacyTracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any SpanProtocol) async throws -> T + _ 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) defer { span.end() } @@ -236,7 +236,7 @@ extension LegacyTracerProtocol { @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) extension TracerProtocol { - /// Start a new span returning an existential ``SpanProtocol`` reference. + /// 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. @@ -273,7 +273,7 @@ extension TracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line - ) -> any SpanProtocol { + ) -> any Span { self.startSpan( operationName, baggage: baggage(), @@ -285,7 +285,7 @@ extension TracerProtocol { ) } - /// Start a new ``SpanProtocol`` and automatically end when the `operation` completes, + /// 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` @@ -326,7 +326,7 @@ extension TracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any SpanProtocol) throws -> T + _ operation: (any Span) throws -> T ) rethrows -> T { try self.withSpan( operationName, @@ -341,7 +341,7 @@ extension TracerProtocol { } } - /// Start a new ``SpanProtocol`` and automatically end when the `operation` completes, + /// 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` @@ -384,7 +384,7 @@ extension TracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any SpanProtocol) async throws -> T + _ operation: (any Span) async throws -> T ) async rethrows -> T { try await self.withSpan( operationName, @@ -408,7 +408,7 @@ extension TracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (any SpanProtocol) async throws -> T + _ 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 ee9d8560..9017334d 100644 --- a/Sources/Tracing/TracerProtocol.swift +++ b/Sources/Tracing/TracerProtocol.swift @@ -22,11 +22,11 @@ import Dispatch #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 ``SpanProtocol``. +/// A tracer is a special kind of instrument with the added ability to start a ``Span``. @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage public protocol TracerProtocol: LegacyTracerProtocol { /// The concrete type of span this tracer will be producing/ - associatedtype Span: SpanProtocol + associatedtype TracerSpan: Span /// Start a new ``Span`` with the given `Baggage`. /// @@ -60,7 +60,7 @@ public protocol TracerProtocol: LegacyTracerProtocol { function: String, file fileID: String, line: UInt - ) -> Self.Span + ) -> TracerSpan } @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage @@ -97,7 +97,7 @@ extension TracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line - ) -> Self.Span { + ) -> TracerSpan { self.startSpan( operationName, baggage: baggage(), @@ -124,7 +124,7 @@ extension TracerProtocol { /// 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 ``SpanProtocol/end()`` the span explicitly, because at the end of the `withSpan` + /// - 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: @@ -146,7 +146,7 @@ extension TracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (Self.Span) throws -> T + _ operation: (TracerSpan) throws -> T ) rethrows -> T { let span = self.startSpan( operationName, @@ -177,7 +177,7 @@ extension TracerProtocol { /// 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 ``SpanProtocol/end()`` the span explicitly, because at the end of the `withSpan` + /// - 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: @@ -200,7 +200,7 @@ extension TracerProtocol { function: String = #function, file fileID: String = #fileID, line: UInt = #line, - _ operation: (Self.Span) async throws -> T + _ operation: (TracerSpan) async throws -> T ) async rethrows -> T { let span = self.startSpan( operationName, diff --git a/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift b/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift index 18cca95a..8281fc58 100644 --- a/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift +++ b/Sources/_TracingBenchmarks/SpanAttributesDSLBenchmark.swift @@ -69,7 +69,7 @@ public let SpanAttributesDSLBenchmarks: [BenchmarkInfo] = [ ), ] -private var span: (any SpanProtocol)! +private var span: (any Span)! private func setUp() { span = InstrumentationSystem.legacyTracer.startAnySpan("something", baggage: .topLevel) diff --git a/Tests/TracingTests/DynamicTracepointTracerTests.swift b/Tests/TracingTests/DynamicTracepointTracerTests.swift index be23c089..953a01cb 100644 --- a/Tests/TracingTests/DynamicTracepointTracerTests.swift +++ b/Tests/TracingTests/DynamicTracepointTracerTests.swift @@ -164,7 +164,7 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { } private(set) var spans: [TracepointSpan] = [] - var onEndSpan: (SpanProtocol) -> Void = { _ in + var onEndSpan: (Span) -> Void = { _ in } func startAnySpan( @@ -175,7 +175,7 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { function: String, file fileID: String, line: UInt - ) -> any SpanProtocol { + ) -> any Span { let tracepoint = TracepointID(function: function, fileID: fileID, line: line) guard self.shouldRecord(tracepoint: tracepoint) else { return TracepointSpan.notRecording(file: fileID, line: line) @@ -255,7 +255,7 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { extension DynamicTracepointTestTracer { /// Only intended to be used in single-threaded testing. - final class TracepointSpan: Tracing.SpanProtocol { + final class TracepointSpan: Tracing.Span { private let kind: SpanKind private var status: SpanStatus? @@ -333,7 +333,7 @@ extension DynamicTracepointTestTracer { #if compiler(>=5.7.0) extension DynamicTracepointTestTracer: TracerProtocol { - typealias Span = TracepointSpan + typealias TracerSpan = TracepointSpan func startSpan(_ operationName: String, baggage: @autoclosure () -> Baggage, diff --git a/Tests/TracingTests/SpanTests.swift b/Tests/TracingTests/SpanTests.swift index 1e76fe87..88dad81d 100644 --- a/Tests/TracingTests/SpanTests.swift +++ b/Tests/TracingTests/SpanTests.swift @@ -93,8 +93,6 @@ final class SpanTests: XCTestCase { XCTAssertEqual(attributes["meaning.of.life"]?.toSpanAttribute(), SpanAttribute.int(42)) XCTAssertEqual(attributes["alive"]?.toSpanAttribute(), SpanAttribute.bool(false)) - // using swift 5.2, we can improve upon that by using type-safe, keypath-based subscripts: - #if swift(>=5.2) // An import like: `import TracingOpenTelemetrySupport` can enable type-safe well defined attributes, // e.g. as defined in https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/trace/semantic_conventions attributes.name = "kappa" @@ -104,12 +102,10 @@ final class SpanTests: XCTestCase { XCTAssertEqual(attributes.name, SpanAttribute.string("kappa")) XCTAssertEqual(attributes.name, "kappa") XCTAssertEqual(attributes.sampleHttp.statusCode, 200) - #endif } func testSpanAttributesCustomValue() { - #if swift(>=5.2) - var attributes: SpanAttributes = [:] + let attributes: SpanAttributes = [:] // normally we can use just the span attribute values, and it is not type safe or guided in any way: attributes.sampleHttp.customType = CustomAttributeValue() @@ -117,7 +113,6 @@ final class SpanTests: XCTestCase { XCTAssertEqual(attributes["http.custom_value"]?.toSpanAttribute(), SpanAttribute.stringConvertible(CustomAttributeValue())) XCTAssertEqual(String(reflecting: attributes.sampleHttp.customType), "Optional(CustomAttributeValue())") XCTAssertEqual(attributes.sampleHttp.customType, CustomAttributeValue()) - #endif } func testSpanAttributesAreIterable() { diff --git a/Tests/TracingTests/TestTracer.swift b/Tests/TracingTests/TestTracer.swift index 72e8c6ff..21d04cd2 100644 --- a/Tests/TracingTests/TestTracer.swift +++ b/Tests/TracingTests/TestTracer.swift @@ -31,7 +31,7 @@ final class TestTracer: LegacyTracerProtocol { function: String, file fileID: String, line: UInt - ) -> any SpanProtocol { + ) -> any Span { let span = TestSpan( operationName: operationName, startTime: time, @@ -119,7 +119,7 @@ extension Baggage { } /// Only intended to be used in single-threaded testing. -final class TestSpan: SpanProtocol { +final class TestSpan: Span { private let kind: SpanKind private var status: SpanStatus? diff --git a/Tests/TracingTests/TracedLock.swift b/Tests/TracingTests/TracedLock.swift index 92043a4e..720d40ca 100644 --- a/Tests/TracingTests/TracedLock.swift +++ b/Tests/TracingTests/TracedLock.swift @@ -21,7 +21,7 @@ final class TracedLock { let name: String let underlyingLock: NSLock - var activeSpan: SpanProtocol? + var activeSpan: Span? init(name: String) { self.name = name diff --git a/Tests/TracingTests/TracedLockTests.swift b/Tests/TracingTests/TracedLockTests.swift index 3edbeedf..1aff5988 100644 --- a/Tests/TracingTests/TracedLockTests.swift +++ b/Tests/TracingTests/TracedLockTests.swift @@ -68,7 +68,7 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { function: String, file fileID: String, line: UInt - ) -> any SpanProtocol { + ) -> any Span { TracedLockPrintlnSpan( operationName: operationName, startTime: time, @@ -97,7 +97,7 @@ private final class TracedLockPrintlnTracer: LegacyTracerProtocol { Extract: Extractor, Carrier == Extract.Carrier {} - final class TracedLockPrintlnSpan: SpanProtocol { + final class TracedLockPrintlnSpan: Span { private let kind: SpanKind private var status: SpanStatus? diff --git a/Tests/TracingTests/TracerTests.swift b/Tests/TracingTests/TracerTests.swift index 389cd85d..06aab388 100644 --- a/Tests/TracingTests/TracerTests.swift +++ b/Tests/TracingTests/TracerTests.swift @@ -123,11 +123,11 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: SpanProtocol) -> String { + func operation(span: Span) -> String { "world" } - let value = tracer.withAnySpan("hello") { (span: SpanProtocol) -> String in + let value = tracer.withAnySpan("hello") { (span: Span) -> String in XCTAssertEqual(span.baggage.traceID, Baggage.current?.traceID) return operation(span: span) } @@ -152,7 +152,7 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: SpanProtocol) throws -> String { + func operation(span: Span) throws -> String { throw ExampleSpanError() } @@ -182,12 +182,12 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: SpanProtocol) async throws -> String { + func operation(span: Span) async throws -> String { "world" } try self.testAsync { - let value = try await tracer.withAnySpan("hello") { (span: SpanProtocol) -> String in + let value = try await tracer.withAnySpan("hello") { (span: Span) -> String in XCTAssertEqual(span.baggage.traceID, Baggage.current?.traceID) return try await operation(span: span) } @@ -212,14 +212,14 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: SpanProtocol) async -> String { + func operation(span: Span) async -> String { "world" } self.testAsync { var fromNonAsyncWorld = Baggage.topLevel fromNonAsyncWorld.traceID = "1234-5678" - let value = await tracer.withAnySpan("hello", baggage: fromNonAsyncWorld) { (span: SpanProtocol) -> String in + let value = await tracer.withAnySpan("hello", baggage: fromNonAsyncWorld) { (span: Span) -> String in XCTAssertEqual(span.baggage.traceID, Baggage.current?.traceID) XCTAssertEqual(span.baggage.traceID, fromNonAsyncWorld.traceID) return await operation(span: span) @@ -244,7 +244,7 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: SpanProtocol) async throws -> String { + func operation(span: Span) async throws -> String { throw ExampleSpanError() } @@ -274,7 +274,7 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: SpanProtocol) async throws -> String { + func operation(span: Span) async throws -> String { throw ExampleSpanError() } @@ -304,7 +304,7 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: SpanProtocol) throws -> String { + func operation(span: Span) throws -> String { throw ExampleSpanError() } From f43657ab2ceb9cc6b62ff6b5bf044e9b3e7cd85f Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 16 Mar 2023 19:33:04 +0900 Subject: [PATCH 2/3] Enable struct Spans with reference semantics; optimal NoopSpan **Motivation:** We want a noop span to be NOT ref counted. **Modifications:** Allow spans to be value types through they must have reference semantics **Result:** Efficient noop spans --- Sources/Tracing/NoOpTracer.swift | 6 +- Sources/Tracing/SpanProtocol.swift | 199 +++++++----------- .../BenchmarkTools.swift | 2 +- Sources/_TracingBenchmarks/main.swift | 2 +- .../DynamicTracepointTracerTests.swift | 2 +- Tests/TracingTests/SpanTests.swift | 24 +-- Tests/TracingTests/TestTracer.swift | 2 - Tests/TracingTests/TracedLock.swift | 2 +- Tests/TracingTests/TracerTests.swift | 20 +- 9 files changed, 99 insertions(+), 160 deletions(-) diff --git a/Sources/Tracing/NoOpTracer.swift b/Sources/Tracing/NoOpTracer.swift index 5694c89a..2c930168 100644 --- a/Sources/Tracing/NoOpTracer.swift +++ b/Sources/Tracing/NoOpTracer.swift @@ -47,7 +47,7 @@ public struct NoOpTracer: LegacyTracerProtocol { // no-op } - public final class NoOpSpan: Span { + public struct NoOpSpan: Span { public let baggage: Baggage public var isRecording: Bool { false @@ -57,7 +57,7 @@ public struct NoOpTracer: LegacyTracerProtocol { get { "noop" } - set { + nonmutating set { // ignore } } @@ -78,7 +78,7 @@ public struct NoOpTracer: LegacyTracerProtocol { get { [:] } - set { + nonmutating set { // ignore } } diff --git a/Sources/Tracing/SpanProtocol.swift b/Sources/Tracing/SpanProtocol.swift index e650f51a..ef70d753 100644 --- a/Sources/Tracing/SpanProtocol.swift +++ b/Sources/Tracing/SpanProtocol.swift @@ -25,8 +25,10 @@ import struct Dispatch.DispatchWallTime /// /// Creating a `Span` is delegated to a ``Tracer`` and end users should never create them directly. /// +/// ### +/// /// - SeeAlso: For more details refer to the [OpenTelemetry Specification: Span](https://github.com/open-telemetry/opentelemetry-specification/blob/v0.7.0/specification/trace/api.md#span) which this type is compatible with. -public protocol Span: AnyObject, _SwiftTracingSendableSpan { +public protocol Span: _SwiftTracingSendableSpan { /// The read-only `Baggage` of this `Span`, set when starting this `Span`. var baggage: Baggage { get } @@ -45,7 +47,10 @@ public protocol Span: AnyObject, _SwiftTracingSendableSpan { /// - 2.1) "Route Not Found" -> Record error /// - 2.2) "Route Found" -> Rename to route (`/users/1` becomes `/users/:userID`) /// - 3) End span - var operationName: String { get set } + var operationName: String { + get + nonmutating set + } /// Set the status. /// @@ -65,7 +70,10 @@ public protocol Span: AnyObject, _SwiftTracingSendableSpan { func recordError(_ error: Error, attributes: SpanAttributes) /// The attributes describing this `Span`. - var attributes: SpanAttributes { get set } + var attributes: SpanAttributes { + get + nonmutating set + } /// Returns true if this `Span` is recording information like events, attributes, status, etc. var isRecording: Bool { get } @@ -114,7 +122,7 @@ extension Span { /// /// - Parameter other: The `Span` to link to. /// - Parameter attributes: The ``SpanAttributes`` describing this link. Defaults to no attributes. - public func addLink(_ other: Span, attributes: SpanAttributes = [:]) { + public func addLink(_ other: Self, attributes: SpanAttributes = [:]) { self.addLink(SpanLink(baggage: other.baggage, attributes: attributes)) } } @@ -183,10 +191,16 @@ public protocol SpanAttributeNamespace { var attributes: SpanAttributes { get set } - subscript(dynamicMember dynamicMember: KeyPath>) -> T? where T: SpanAttributeConvertible { get set } + subscript(dynamicMember dynamicMember: KeyPath>) -> T? where T: SpanAttributeConvertible { + get + set + } subscript(dynamicMember dynamicMember: KeyPath) -> Namespace - where Namespace: SpanAttributeNamespace { get } + where Namespace: SpanAttributeNamespace + { + get + } } public protocol NestedSpanAttributesProtocol { @@ -217,14 +231,17 @@ extension SpanAttributeNamespace { let key = NestedSpanAttributes.__namespace[keyPath: dynamicMember] let spanAttribute = self.attributes[key.name]?.toSpanAttribute() switch spanAttribute { - case .int(let int): - switch T.self { - case is Int.Type: return (Int(exactly: int) as! T) - case is Int8.Type: return (Int8(exactly: int) as! T) - case is Int16.Type: return (Int16(exactly: int) as! T) - case is Int32.Type: return (Int32(exactly: int) as! T) - case is Int64.Type: return (int as! T) - default: return nil + case .int32(let value): + if T.self == Int.self { + return (Int(exactly: value) as! T) + } else { + return value as? T + } + case .int64(let value): + if T.self == Int.self { + return (Int(exactly: value) as! T) + } else { + return value as? T } default: if let value = spanAttribute?.anyValue { @@ -255,8 +272,11 @@ extension SpanAttributeNamespace { public enum SpanAttribute: Equatable { public typealias Key = SpanAttributeKey - case int(Int64) - case intArray([Int64]) + case int32(Int32) + case int64(Int64) + + case int32Array([Int32]) + case int64Array([Int64]) case double(Double) case doubleArray([Double]) @@ -267,32 +287,14 @@ public enum SpanAttribute: Equatable { case string(String) case stringArray([String]) - #if swift(>=5.6) + case __DO_NOT_SWITCH_EXHAUSTIVELY_OVER_THIS_ENUM + case stringConvertible(CustomStringConvertible & Sendable) case stringConvertibleArray([CustomStringConvertible & Sendable]) - #else - case stringConvertible(CustomStringConvertible) - case stringConvertibleArray([CustomStringConvertible]) - #endif - - #if swift(>=5.2) - // older swifts get confused and can't resolve if we mean the `case int(Int64)` or any of those overloads - public static func int(_ value: Int) -> SpanAttribute { - .int(Int64(value)) - } - - public static func int(_ value: Int8) -> SpanAttribute { - .int(Int64(value)) - } - - public static func int(_ value: Int16) -> SpanAttribute { - .int(Int64(value)) - } - public static func int(_ value: Int32) -> SpanAttribute { - .int(Int64(value)) + public static func int(_ value: Int64) -> SpanAttribute { + .int64(value) } - #endif /// This is a "magic value" that is used to enable the KeyPath based accessors to specific attributes. internal static var _namespace: SpanAttribute { @@ -301,9 +303,13 @@ public enum SpanAttribute: Equatable { internal var anyValue: Any { switch self { - case .int(let value): + case .int32(let value): + return value + case .int64(let value): return value - case .intArray(let value): + case .int32Array(let value): + return value + case .int64Array(let value): return value case .double(let value): return value @@ -321,13 +327,17 @@ public enum SpanAttribute: Equatable { return value case .stringConvertibleArray(let value): return value + case .__DO_NOT_SWITCH_EXHAUSTIVELY_OVER_THIS_ENUM: + fatalError("Cannot have values of __DO_NOT_SWITCH_EXHAUSTIVELY_OVER_THIS_ENUM") } } public static func == (lhs: SpanAttribute, rhs: SpanAttribute) -> Bool { switch (lhs, rhs) { - case (.int(let l), .int(let r)): return l == r - case (.intArray(let l), .intArray(let r)): return l == r + case (.int32(let l), .int32(let r)): return l == r + case (.int64(let l), .int64(let r)): return l == r + case (.int32Array(let l), .int32Array(let r)): return l == r + case (.int64Array(let l), .int64Array(let r)): return l == r case (.double(let l), .double(let r)): return l == r case (.doubleArray(let l), .doubleArray(let r)): return l == r case (.bool(let l), .bool(let r)): return l == r @@ -336,16 +346,7 @@ public enum SpanAttribute: Equatable { case (.stringArray(let l), .stringArray(let r)): return l == r case (.stringConvertible(let l), .stringConvertible(let r)): return "\(l)" == "\(r)" case (.stringConvertibleArray(let l), .stringConvertibleArray(let r)): return "\(l)" == "\(r)" - case (.int, _), - (.intArray, _), - (.double, _), - (.doubleArray, _), - (.bool, _), - (.boolArray, _), - (.string, _), - (.stringArray, _), - (.stringConvertible, _), - (.stringConvertibleArray, _): + default: return false } } @@ -369,31 +370,19 @@ public protocol SpanAttributeConvertible { extension Array where Element == Int { public func toSpanAttribute() -> SpanAttribute { - .intArray(self.map(Int64.init)) - } -} - -extension Array where Element == Int8 { - public func toSpanAttribute() -> SpanAttribute { - .intArray(self.map(Int64.init)) - } -} - -extension Array where Element == Int16 { - public func toSpanAttribute() -> SpanAttribute { - .intArray(self.map(Int64.init)) - } -} - -extension Array where Element == Int32 { - public func toSpanAttribute() -> SpanAttribute { - .intArray(self.map(Int64.init)) + if MemoryLayout.stride == 8 { + return .int64Array(self.map(Int64.init)) + } else if MemoryLayout.stride == 4 { + return .int32Array(self.map(Int32.init)) + } else { + fatalError("Not supported Int width: \(MemoryLayout.stride)") + } } } extension Array where Element == Int64 { public func toSpanAttribute() -> SpanAttribute { - .intArray(self) + .int64Array(self) } } @@ -406,33 +395,19 @@ extension Array where Element == Double { // fallback implementation extension Array: SpanAttributeConvertible where Element: SpanAttributeConvertible { public func toSpanAttribute() -> SpanAttribute { - if let value = self as? [Int] { - return .intArray(value.map(Int64.init)) - } else if let value = self as? [Int8] { - return .intArray(value.map(Int64.init)) - } else if let value = self as? [Int16] { - return .intArray(value.map(Int64.init)) - } else if let value = self as? [Int32] { - return .intArray(value.map(Int64.init)) + if let value = self as? [Int32] { + return .int32Array(value) } else if let value = self as? [Int64] { - return .intArray(value) + return .int64Array(value) } else if let value = self as? [Double] { return .doubleArray(value) } else if let value = self as? [Bool] { return .boolArray(value) } else if let value = self as? [String] { return .stringArray(value) - } - #if swift(>=5.6.0) - if let value = self as? [CustomStringConvertible & Sendable] { - return .stringConvertibleArray(value) - } - #else - if let value = self as? [CustomStringConvertible] { + } else if let value = self as? [CustomStringConvertible & Sendable] { return .stringConvertibleArray(value) } - #endif - fatalError("Not supported SpanAttribute array type: \(type(of: self))") } } @@ -469,31 +444,19 @@ extension SpanAttribute: ExpressibleByIntegerLiteral { extension Int: SpanAttributeConvertible { public func toSpanAttribute() -> SpanAttribute { - .int(Int64(self)) - } -} - -extension Int8: SpanAttributeConvertible { - public func toSpanAttribute() -> SpanAttribute { - .int(Int64(self)) - } -} - -extension Int16: SpanAttributeConvertible { - public func toSpanAttribute() -> SpanAttribute { - .int(Int64(self)) - } -} - -extension Int32: SpanAttributeConvertible { - public func toSpanAttribute() -> SpanAttribute { - .int(Int64(self)) + if MemoryLayout.stride == 8 { + return .int64(Int64(self)) + } else if MemoryLayout.stride == 4 { + return .int32(Int32(exactly: self)!) + } else { + fatalError("Not supported int width: \(MemoryLayout.stride)") + } } } extension Int64: SpanAttributeConvertible { public func toSpanAttribute() -> SpanAttribute { - .int(self) + .int64(self) } } @@ -536,19 +499,12 @@ extension SpanAttribute: ExpressibleByBooleanLiteral { // ==== ---------------------------------------------------------------------------------------------------------------- // MARK: SpanAttributes: Namespaces -#if swift(>=5.2) /// A container of ``SpanAttribute``s. @dynamicMemberLookup public struct SpanAttributes: Equatable { private var _attributes = [String: SpanAttribute]() } -#else -public struct SpanAttributes: Equatable { - private var _attributes = [String: SpanAttribute]() -} -#endif - extension SpanAttributes { /// Create a set of attributes by wrapping the given dictionary. /// @@ -695,22 +651,18 @@ public struct SpanLink { public let attributes: SpanAttributes /// Create a new `SpanLink`. + /// /// - Parameters: /// - baggage: The `Baggage` identifying the targeted ``Span``. /// - attributes: ``SpanAttributes`` that further describe the link. Defaults to no attributes. - public init(baggage: Baggage, attributes: SpanAttributes = [:]) { + public init(baggage: Baggage, attributes: SpanAttributes) { self.baggage = baggage self.attributes = attributes } } -#if compiler(>=5.6) @preconcurrency public protocol _SwiftTracingSendableSpan: Sendable {} -#else -public protocol _SwiftTracingSendableSpan {} -#endif -#if compiler(>=5.6) extension SpanAttributes: Sendable {} extension SpanAttribute: Sendable {} // @unchecked because some payloads are CustomStringConvertible extension SpanStatus: Sendable {} @@ -718,4 +670,3 @@ extension SpanEvent: Sendable {} extension SpanKind: Sendable {} extension SpanStatus.Code: Sendable {} extension SpanLink: Sendable {} -#endif diff --git a/Sources/_TracingBenchmarkTools/BenchmarkTools.swift b/Sources/_TracingBenchmarkTools/BenchmarkTools.swift index 283fe7bd..e48793d1 100644 --- a/Sources/_TracingBenchmarkTools/BenchmarkTools.swift +++ b/Sources/_TracingBenchmarkTools/BenchmarkTools.swift @@ -179,7 +179,7 @@ public func Random() -> Int64 { lfsrRandomGenerator.randInt() } -@inlinable // FIXME(inline-always) +@inlinable @inline(__always) public func CheckResults( _ resultsMatch: Bool, diff --git a/Sources/_TracingBenchmarks/main.swift b/Sources/_TracingBenchmarks/main.swift index 4ae4b3aa..9df14c9d 100644 --- a/Sources/_TracingBenchmarks/main.swift +++ b/Sources/_TracingBenchmarks/main.swift @@ -37,6 +37,6 @@ private func registerBenchmark(_ name: String, _ function: @escaping (Int) -> Vo registerBenchmark(BenchmarkInfo(name: name, runFunction: function, tags: tags)) } -registerBenchmark(SpanAttributesDSLBenchmarks) +// registerBenchmark(SpanAttributesDSLBenchmarks) main() diff --git a/Tests/TracingTests/DynamicTracepointTracerTests.swift b/Tests/TracingTests/DynamicTracepointTracerTests.swift index 953a01cb..1904d63f 100644 --- a/Tests/TracingTests/DynamicTracepointTracerTests.swift +++ b/Tests/TracingTests/DynamicTracepointTracerTests.swift @@ -164,7 +164,7 @@ final class DynamicTracepointTestTracer: LegacyTracerProtocol { } private(set) var spans: [TracepointSpan] = [] - var onEndSpan: (Span) -> Void = { _ in + var onEndSpan: (any Span) -> Void = { _ in } func startAnySpan( diff --git a/Tests/TracingTests/SpanTests.swift b/Tests/TracingTests/SpanTests.swift index 88dad81d..85d6009e 100644 --- a/Tests/TracingTests/SpanTests.swift +++ b/Tests/TracingTests/SpanTests.swift @@ -44,7 +44,7 @@ final class SpanTests: XCTestCase { func testSpanAttributeIsExpressibleByIntegerLiteral() { let intAttribute: SpanAttribute = 42 - guard case .int(let intValue) = intAttribute else { + guard case .int64(let intValue) = intAttribute else { XCTFail("Expected int attribute, got \(intAttribute).") return } @@ -101,11 +101,13 @@ final class SpanTests: XCTestCase { XCTAssertEqual(attributes.name, SpanAttribute.string("kappa")) XCTAssertEqual(attributes.name, "kappa") + print("attributes", attributes) XCTAssertEqual(attributes.sampleHttp.statusCode, 200) + XCTAssertEqual(attributes.sampleHttp.codesArray, [1, 2, 3]) } func testSpanAttributesCustomValue() { - let attributes: SpanAttributes = [:] + var attributes: SpanAttributes = [:] // normally we can use just the span attribute values, and it is not type safe or guided in any way: attributes.sampleHttp.customType = CustomAttributeValue() @@ -127,7 +129,7 @@ final class SpanTests: XCTestCase { dictionary[name] = attribute } - guard case .some(.int) = dictionary["0"], case .some(.bool) = dictionary["1"], case .some(.string) = dictionary["2"] else { + guard case .some(.int64) = dictionary["0"], case .some(.bool) = dictionary["1"], case .some(.string) = dictionary["2"] else { XCTFail("Expected all attributes to be copied to the dictionary.") return } @@ -174,11 +176,7 @@ final class SpanTests: XCTestCase { ) var attributes = SpanAttributes() - #if swift(>=5.2) attributes.sampleHttp.statusCode = 418 - #else - attributes["http.status_code"] = 418 - #endif child.addLink(parent, attributes: attributes) XCTAssertEqual(child.links.count, 1) @@ -186,7 +184,7 @@ final class SpanTests: XCTestCase { #if swift(>=5.2) XCTAssertEqual(child.links[0].attributes.sampleHttp.statusCode, 418) #endif - guard case .some(.int(let statusCode)) = child.links[0].attributes["http.status_code"]?.toSpanAttribute() else { + guard case .some(.int64(let statusCode)) = child.links[0].attributes["http.status_code"]?.toSpanAttribute() else { XCTFail("Expected int value for http.status_code") return } @@ -203,7 +201,6 @@ extension SpanAttribute { } } -#if swift(>=5.2) extension SpanAttributes { public var sampleHttp: HTTPAttributes { get { @@ -239,7 +236,7 @@ public struct HTTPAttributes: SpanAttributeNamespace { } } -public struct CustomAttributeValue: Equatable, _CustomAttributeValueSendable, CustomStringConvertible, SpanAttributeConvertible { +public struct CustomAttributeValue: Equatable, Sendable, CustomStringConvertible, SpanAttributeConvertible { public func toSpanAttribute() -> SpanAttribute { .stringConvertible(self) } @@ -248,13 +245,6 @@ public struct CustomAttributeValue: Equatable, _CustomAttributeValueSendable, Cu "CustomAttributeValue()" } } -#endif - -#if swift(>=5.6.0) -typealias _CustomAttributeValueSendable = Sendable -#else -typealias _CustomAttributeValueSendable = Any -#endif private struct TestBaggageContextKey: BaggageKey { typealias Value = String diff --git a/Tests/TracingTests/TestTracer.swift b/Tests/TracingTests/TestTracer.swift index 21d04cd2..44940f92 100644 --- a/Tests/TracingTests/TestTracer.swift +++ b/Tests/TracingTests/TestTracer.swift @@ -187,7 +187,5 @@ final class TestSpan: Span { } } -#if compiler(>=5.6.0) extension TestTracer: @unchecked Sendable {} // only intended for single threaded testing extension TestSpan: @unchecked Sendable {} // only intended for single threaded testing -#endif diff --git a/Tests/TracingTests/TracedLock.swift b/Tests/TracingTests/TracedLock.swift index 720d40ca..946a2f18 100644 --- a/Tests/TracingTests/TracedLock.swift +++ b/Tests/TracingTests/TracedLock.swift @@ -21,7 +21,7 @@ final class TracedLock { let name: String let underlyingLock: NSLock - var activeSpan: Span? + var activeSpan: (any Span)? init(name: String) { self.name = name diff --git a/Tests/TracingTests/TracerTests.swift b/Tests/TracingTests/TracerTests.swift index 06aab388..8cff8df0 100644 --- a/Tests/TracingTests/TracerTests.swift +++ b/Tests/TracingTests/TracerTests.swift @@ -123,11 +123,11 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: Span) -> String { + func operation(span: any Span) -> String { "world" } - let value = tracer.withAnySpan("hello") { (span: Span) -> String in + let value = tracer.withAnySpan("hello") { (span: any Span) -> String in XCTAssertEqual(span.baggage.traceID, Baggage.current?.traceID) return operation(span: span) } @@ -152,7 +152,7 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: Span) throws -> String { + func operation(span: any Span) throws -> String { throw ExampleSpanError() } @@ -182,12 +182,12 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: Span) async throws -> String { + func operation(span: any Span) async throws -> String { "world" } try self.testAsync { - let value = try await tracer.withAnySpan("hello") { (span: Span) -> String in + let value = try await tracer.withAnySpan("hello") { (span: any Span) -> String in XCTAssertEqual(span.baggage.traceID, Baggage.current?.traceID) return try await operation(span: span) } @@ -212,14 +212,14 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: Span) async -> String { + func operation(span: any Span) async -> String { "world" } self.testAsync { var fromNonAsyncWorld = Baggage.topLevel fromNonAsyncWorld.traceID = "1234-5678" - let value = await tracer.withAnySpan("hello", baggage: fromNonAsyncWorld) { (span: Span) -> String in + let value = await tracer.withAnySpan("hello", baggage: fromNonAsyncWorld) { (span: any Span) -> String in XCTAssertEqual(span.baggage.traceID, Baggage.current?.traceID) XCTAssertEqual(span.baggage.traceID, fromNonAsyncWorld.traceID) return await operation(span: span) @@ -244,7 +244,7 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: Span) async throws -> String { + func operation(span: any Span) async throws -> String { throw ExampleSpanError() } @@ -274,7 +274,7 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: Span) async throws -> String { + func operation(span: any Span) async throws -> String { throw ExampleSpanError() } @@ -304,7 +304,7 @@ final class TracerTests: XCTestCase { var spanEnded = false tracer.onEndSpan = { _ in spanEnded = true } - func operation(span: Span) throws -> String { + func operation(span: any Span) throws -> String { throw ExampleSpanError() } From 84e5f503128d12acd858ae3c287f67885144c6d9 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Mon, 20 Mar 2023 19:11:55 +0900 Subject: [PATCH 3/3] review followup --- Sources/Tracing/SpanProtocol.swift | 7 ++++++- Sources/_TracingBenchmarks/main.swift | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Sources/Tracing/SpanProtocol.swift b/Sources/Tracing/SpanProtocol.swift index ef70d753..7ec5d1ef 100644 --- a/Sources/Tracing/SpanProtocol.swift +++ b/Sources/Tracing/SpanProtocol.swift @@ -25,7 +25,12 @@ import struct Dispatch.DispatchWallTime /// /// Creating a `Span` is delegated to a ``Tracer`` and end users should never create them directly. /// -/// ### +/// ### Reference semantics +/// A `Span` always exhibits reference semantics. Even if a span were to be implemented using a struct (or enum), +/// it must exhibit reference semantics. In other words, passing around a `Span` object and mutating it from multiple +/// places must mutate the same underlying storage, and must do so safely (i.e. take locks or use other synchronization +/// mechanisms to protect the mutations). This is because conceptually a span is not a value, and refers to a specific +/// resource that must be started, accumulate all possible information from the span's duration, and ended exactly once. /// /// - SeeAlso: For more details refer to the [OpenTelemetry Specification: Span](https://github.com/open-telemetry/opentelemetry-specification/blob/v0.7.0/specification/trace/api.md#span) which this type is compatible with. public protocol Span: _SwiftTracingSendableSpan { diff --git a/Sources/_TracingBenchmarks/main.swift b/Sources/_TracingBenchmarks/main.swift index 9df14c9d..4ae4b3aa 100644 --- a/Sources/_TracingBenchmarks/main.swift +++ b/Sources/_TracingBenchmarks/main.swift @@ -37,6 +37,6 @@ private func registerBenchmark(_ name: String, _ function: @escaping (Int) -> Vo registerBenchmark(BenchmarkInfo(name: name, runFunction: function, tags: tags)) } -// registerBenchmark(SpanAttributesDSLBenchmarks) +registerBenchmark(SpanAttributesDSLBenchmarks) main()