Skip to content

Commit b522350

Browse files
committed
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
1 parent a7e66b3 commit b522350

File tree

10 files changed

+255
-316
lines changed

10 files changed

+255
-316
lines changed

Sources/Tracing/NoOpTracer.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public struct NoOpTracer: LegacyTracerProtocol {
4747
// no-op
4848
}
4949

50-
public final class NoOpSpan: Span {
50+
public struct NoOpSpan: Span {
5151
public let baggage: Baggage
5252
public var isRecording: Bool {
5353
false
@@ -57,7 +57,7 @@ public struct NoOpTracer: LegacyTracerProtocol {
5757
get {
5858
"noop"
5959
}
60-
set {
60+
nonmutating set {
6161
// ignore
6262
}
6363
}
@@ -78,7 +78,7 @@ public struct NoOpTracer: LegacyTracerProtocol {
7878
get {
7979
[:]
8080
}
81-
set {
81+
nonmutating set {
8282
// ignore
8383
}
8484
}

Sources/Tracing/SpanProtocol.swift

+75-124
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ import struct Dispatch.DispatchWallTime
2525
///
2626
/// Creating a `Span` is delegated to a ``Tracer`` and end users should never create them directly.
2727
///
28+
/// ###
29+
///
2830
/// - 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.
29-
public protocol Span: AnyObject, _SwiftTracingSendableSpan {
31+
public protocol Span: _SwiftTracingSendableSpan {
3032
/// The read-only `Baggage` of this `Span`, set when starting this `Span`.
3133
var baggage: Baggage { get }
3234

@@ -45,7 +47,10 @@ public protocol Span: AnyObject, _SwiftTracingSendableSpan {
4547
/// - 2.1) "Route Not Found" -> Record error
4648
/// - 2.2) "Route Found" -> Rename to route (`/users/1` becomes `/users/:userID`)
4749
/// - 3) End span
48-
var operationName: String { get set }
50+
var operationName: String {
51+
get
52+
nonmutating set
53+
}
4954

5055
/// Set the status.
5156
///
@@ -65,7 +70,10 @@ public protocol Span: AnyObject, _SwiftTracingSendableSpan {
6570
func recordError(_ error: Error, attributes: SpanAttributes)
6671

6772
/// The attributes describing this `Span`.
68-
var attributes: SpanAttributes { get set }
73+
var attributes: SpanAttributes {
74+
get
75+
nonmutating set
76+
}
6977

7078
/// Returns true if this `Span` is recording information like events, attributes, status, etc.
7179
var isRecording: Bool { get }
@@ -114,7 +122,7 @@ extension Span {
114122
///
115123
/// - Parameter other: The `Span` to link to.
116124
/// - Parameter attributes: The ``SpanAttributes`` describing this link. Defaults to no attributes.
117-
public func addLink(_ other: Span, attributes: SpanAttributes = [:]) {
125+
public func addLink(_ other: Self, attributes: SpanAttributes = [:]) {
118126
self.addLink(SpanLink(baggage: other.baggage, attributes: attributes))
119127
}
120128
}
@@ -183,10 +191,16 @@ public protocol SpanAttributeNamespace {
183191

184192
var attributes: SpanAttributes { get set }
185193

186-
subscript<T>(dynamicMember dynamicMember: KeyPath<NestedSpanAttributes, SpanAttributeKey<T>>) -> T? where T: SpanAttributeConvertible { get set }
194+
subscript<T>(dynamicMember dynamicMember: KeyPath<NestedSpanAttributes, SpanAttributeKey<T>>) -> T? where T: SpanAttributeConvertible {
195+
get
196+
set
197+
}
187198

188199
subscript<Namespace>(dynamicMember dynamicMember: KeyPath<SpanAttribute, Namespace>) -> Namespace
189-
where Namespace: SpanAttributeNamespace { get }
200+
where Namespace: SpanAttributeNamespace
201+
{
202+
get
203+
}
190204
}
191205

192206
public protocol NestedSpanAttributesProtocol {
@@ -217,14 +231,17 @@ extension SpanAttributeNamespace {
217231
let key = NestedSpanAttributes.__namespace[keyPath: dynamicMember]
218232
let spanAttribute = self.attributes[key.name]?.toSpanAttribute()
219233
switch spanAttribute {
220-
case .int(let int):
221-
switch T.self {
222-
case is Int.Type: return (Int(exactly: int) as! T)
223-
case is Int8.Type: return (Int8(exactly: int) as! T)
224-
case is Int16.Type: return (Int16(exactly: int) as! T)
225-
case is Int32.Type: return (Int32(exactly: int) as! T)
226-
case is Int64.Type: return (int as! T)
227-
default: return nil
234+
case .int32(let value):
235+
if T.self == Int.self {
236+
return (Int(exactly: value) as! T)
237+
} else {
238+
return value as? T
239+
}
240+
case .int64(let value):
241+
if T.self == Int.self {
242+
return (Int(exactly: value) as! T)
243+
} else {
244+
return value as? T
228245
}
229246
default:
230247
if let value = spanAttribute?.anyValue {
@@ -255,8 +272,11 @@ extension SpanAttributeNamespace {
255272
public enum SpanAttribute: Equatable {
256273
public typealias Key = SpanAttributeKey
257274

258-
case int(Int64)
259-
case intArray([Int64])
275+
case int32(Int32)
276+
case int64(Int64)
277+
278+
case int32Array([Int32])
279+
case int64Array([Int64])
260280

261281
case double(Double)
262282
case doubleArray([Double])
@@ -267,32 +287,14 @@ public enum SpanAttribute: Equatable {
267287
case string(String)
268288
case stringArray([String])
269289

270-
#if swift(>=5.6)
290+
case __DO_NOT_SWITCH_EXHAUSTIVELY_OVER_THIS_ENUM
291+
271292
case stringConvertible(CustomStringConvertible & Sendable)
272293
case stringConvertibleArray([CustomStringConvertible & Sendable])
273-
#else
274-
case stringConvertible(CustomStringConvertible)
275-
case stringConvertibleArray([CustomStringConvertible])
276-
#endif
277-
278-
#if swift(>=5.2)
279-
// older swifts get confused and can't resolve if we mean the `case int(Int64)` or any of those overloads
280-
public static func int(_ value: Int) -> SpanAttribute {
281-
.int(Int64(value))
282-
}
283-
284-
public static func int(_ value: Int8) -> SpanAttribute {
285-
.int(Int64(value))
286-
}
287-
288-
public static func int(_ value: Int16) -> SpanAttribute {
289-
.int(Int64(value))
290-
}
291294

292-
public static func int(_ value: Int32) -> SpanAttribute {
293-
.int(Int64(value))
295+
public static func int(_ value: Int64) -> SpanAttribute {
296+
.int64(value)
294297
}
295-
#endif
296298

297299
/// This is a "magic value" that is used to enable the KeyPath based accessors to specific attributes.
298300
internal static var _namespace: SpanAttribute {
@@ -301,9 +303,13 @@ public enum SpanAttribute: Equatable {
301303

302304
internal var anyValue: Any {
303305
switch self {
304-
case .int(let value):
306+
case .int32(let value):
307+
return value
308+
case .int64(let value):
305309
return value
306-
case .intArray(let value):
310+
case .int32Array(let value):
311+
return value
312+
case .int64Array(let value):
307313
return value
308314
case .double(let value):
309315
return value
@@ -321,13 +327,17 @@ public enum SpanAttribute: Equatable {
321327
return value
322328
case .stringConvertibleArray(let value):
323329
return value
330+
case .__DO_NOT_SWITCH_EXHAUSTIVELY_OVER_THIS_ENUM:
331+
fatalError("Cannot have values of __DO_NOT_SWITCH_EXHAUSTIVELY_OVER_THIS_ENUM")
324332
}
325333
}
326334

327335
public static func == (lhs: SpanAttribute, rhs: SpanAttribute) -> Bool {
328336
switch (lhs, rhs) {
329-
case (.int(let l), .int(let r)): return l == r
330-
case (.intArray(let l), .intArray(let r)): return l == r
337+
case (.int32(let l), .int32(let r)): return l == r
338+
case (.int64(let l), .int64(let r)): return l == r
339+
case (.int32Array(let l), .int32Array(let r)): return l == r
340+
case (.int64Array(let l), .int64Array(let r)): return l == r
331341
case (.double(let l), .double(let r)): return l == r
332342
case (.doubleArray(let l), .doubleArray(let r)): return l == r
333343
case (.bool(let l), .bool(let r)): return l == r
@@ -336,16 +346,7 @@ public enum SpanAttribute: Equatable {
336346
case (.stringArray(let l), .stringArray(let r)): return l == r
337347
case (.stringConvertible(let l), .stringConvertible(let r)): return "\(l)" == "\(r)"
338348
case (.stringConvertibleArray(let l), .stringConvertibleArray(let r)): return "\(l)" == "\(r)"
339-
case (.int, _),
340-
(.intArray, _),
341-
(.double, _),
342-
(.doubleArray, _),
343-
(.bool, _),
344-
(.boolArray, _),
345-
(.string, _),
346-
(.stringArray, _),
347-
(.stringConvertible, _),
348-
(.stringConvertibleArray, _):
349+
default:
349350
return false
350351
}
351352
}
@@ -369,31 +370,19 @@ public protocol SpanAttributeConvertible {
369370

370371
extension Array where Element == Int {
371372
public func toSpanAttribute() -> SpanAttribute {
372-
.intArray(self.map(Int64.init))
373-
}
374-
}
375-
376-
extension Array where Element == Int8 {
377-
public func toSpanAttribute() -> SpanAttribute {
378-
.intArray(self.map(Int64.init))
379-
}
380-
}
381-
382-
extension Array where Element == Int16 {
383-
public func toSpanAttribute() -> SpanAttribute {
384-
.intArray(self.map(Int64.init))
385-
}
386-
}
387-
388-
extension Array where Element == Int32 {
389-
public func toSpanAttribute() -> SpanAttribute {
390-
.intArray(self.map(Int64.init))
373+
if MemoryLayout<Int>.stride == 8 {
374+
return .int64Array(self.map(Int64.init))
375+
} else if MemoryLayout<Int>.stride == 4 {
376+
return .int32Array(self.map(Int32.init))
377+
} else {
378+
fatalError("Not supported Int width: \(MemoryLayout<Int>.stride)")
379+
}
391380
}
392381
}
393382

394383
extension Array where Element == Int64 {
395384
public func toSpanAttribute() -> SpanAttribute {
396-
.intArray(self)
385+
.int64Array(self)
397386
}
398387
}
399388

@@ -406,33 +395,19 @@ extension Array where Element == Double {
406395
// fallback implementation
407396
extension Array: SpanAttributeConvertible where Element: SpanAttributeConvertible {
408397
public func toSpanAttribute() -> SpanAttribute {
409-
if let value = self as? [Int] {
410-
return .intArray(value.map(Int64.init))
411-
} else if let value = self as? [Int8] {
412-
return .intArray(value.map(Int64.init))
413-
} else if let value = self as? [Int16] {
414-
return .intArray(value.map(Int64.init))
415-
} else if let value = self as? [Int32] {
416-
return .intArray(value.map(Int64.init))
398+
if let value = self as? [Int32] {
399+
return .int32Array(value)
417400
} else if let value = self as? [Int64] {
418-
return .intArray(value)
401+
return .int64Array(value)
419402
} else if let value = self as? [Double] {
420403
return .doubleArray(value)
421404
} else if let value = self as? [Bool] {
422405
return .boolArray(value)
423406
} else if let value = self as? [String] {
424407
return .stringArray(value)
425-
}
426-
#if swift(>=5.6.0)
427-
if let value = self as? [CustomStringConvertible & Sendable] {
428-
return .stringConvertibleArray(value)
429-
}
430-
#else
431-
if let value = self as? [CustomStringConvertible] {
408+
} else if let value = self as? [CustomStringConvertible & Sendable] {
432409
return .stringConvertibleArray(value)
433410
}
434-
#endif
435-
436411
fatalError("Not supported SpanAttribute array type: \(type(of: self))")
437412
}
438413
}
@@ -469,31 +444,19 @@ extension SpanAttribute: ExpressibleByIntegerLiteral {
469444

470445
extension Int: SpanAttributeConvertible {
471446
public func toSpanAttribute() -> SpanAttribute {
472-
.int(Int64(self))
473-
}
474-
}
475-
476-
extension Int8: SpanAttributeConvertible {
477-
public func toSpanAttribute() -> SpanAttribute {
478-
.int(Int64(self))
479-
}
480-
}
481-
482-
extension Int16: SpanAttributeConvertible {
483-
public func toSpanAttribute() -> SpanAttribute {
484-
.int(Int64(self))
485-
}
486-
}
487-
488-
extension Int32: SpanAttributeConvertible {
489-
public func toSpanAttribute() -> SpanAttribute {
490-
.int(Int64(self))
447+
if MemoryLayout<Int>.stride == 8 {
448+
return .int64(Int64(self))
449+
} else if MemoryLayout<Int>.stride == 4 {
450+
return .int32(Int32(exactly: self)!)
451+
} else {
452+
fatalError("Not supported int width: \(MemoryLayout<Int>.stride)")
453+
}
491454
}
492455
}
493456

494457
extension Int64: SpanAttributeConvertible {
495458
public func toSpanAttribute() -> SpanAttribute {
496-
.int(self)
459+
.int64(self)
497460
}
498461
}
499462

@@ -536,19 +499,12 @@ extension SpanAttribute: ExpressibleByBooleanLiteral {
536499
// ==== ----------------------------------------------------------------------------------------------------------------
537500
// MARK: SpanAttributes: Namespaces
538501

539-
#if swift(>=5.2)
540502
/// A container of ``SpanAttribute``s.
541503
@dynamicMemberLookup
542504
public struct SpanAttributes: Equatable {
543505
private var _attributes = [String: SpanAttribute]()
544506
}
545507

546-
#else
547-
public struct SpanAttributes: Equatable {
548-
private var _attributes = [String: SpanAttribute]()
549-
}
550-
#endif
551-
552508
extension SpanAttributes {
553509
/// Create a set of attributes by wrapping the given dictionary.
554510
///
@@ -695,27 +651,22 @@ public struct SpanLink {
695651
public let attributes: SpanAttributes
696652

697653
/// Create a new `SpanLink`.
654+
///
698655
/// - Parameters:
699656
/// - baggage: The `Baggage` identifying the targeted ``Span``.
700657
/// - attributes: ``SpanAttributes`` that further describe the link. Defaults to no attributes.
701-
public init(baggage: Baggage, attributes: SpanAttributes = [:]) {
658+
public init(baggage: Baggage, attributes: SpanAttributes) {
702659
self.baggage = baggage
703660
self.attributes = attributes
704661
}
705662
}
706663

707-
#if compiler(>=5.6)
708664
@preconcurrency public protocol _SwiftTracingSendableSpan: Sendable {}
709-
#else
710-
public protocol _SwiftTracingSendableSpan {}
711-
#endif
712665

713-
#if compiler(>=5.6)
714666
extension SpanAttributes: Sendable {}
715667
extension SpanAttribute: Sendable {} // @unchecked because some payloads are CustomStringConvertible
716668
extension SpanStatus: Sendable {}
717669
extension SpanEvent: Sendable {}
718670
extension SpanKind: Sendable {}
719671
extension SpanStatus.Code: Sendable {}
720672
extension SpanLink: Sendable {}
721-
#endif

Sources/_TracingBenchmarkTools/BenchmarkTools.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public func Random() -> Int64 {
179179
lfsrRandomGenerator.randInt()
180180
}
181181

182-
@inlinable // FIXME(inline-always)
182+
@inlinable
183183
@inline(__always)
184184
public func CheckResults(
185185
_ resultsMatch: Bool,

0 commit comments

Comments
 (0)