Skip to content

Commit b087d50

Browse files
authored
Merge pull request #100 from slashmo/refactor/tracing-instrumentation
Move TracingInstrument & related types to separate library
2 parents f20b0b2 + 89d8ccd commit b087d50

17 files changed

+197
-40
lines changed

Package.resolved

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ let package = Package(
66
products: [
77
.library(name: "BaggageLogging", targets: ["BaggageLogging"]),
88
.library(name: "Instrumentation", targets: ["Instrumentation"]),
9+
.library(name: "TracingInstrumentation", targets: ["TracingInstrumentation"]),
910
.library(name: "NIOInstrumentation", targets: ["NIOInstrumentation"])
1011
],
1112
dependencies: [
@@ -52,6 +53,21 @@ let package = Package(
5253
]
5354
),
5455

56+
.target(
57+
name: "TracingInstrumentation",
58+
dependencies: [
59+
"Instrumentation"
60+
]
61+
),
62+
.testTarget(
63+
name: "TracingInstrumentationTests",
64+
dependencies: [
65+
"Instrumentation",
66+
"TracingInstrumentation",
67+
"BaggageLogging"
68+
]
69+
),
70+
5571
.target(
5672
name: "NIOInstrumentation",
5773
dependencies: [

Sources/Instrumentation/Instrument.swift

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,3 @@ public protocol Instrument {
6767
Injector.Carrier == Carrier
6868
}
6969

70-
public struct NoOpInstrument: Instrument {
71-
public func inject<Carrier, Injector>(_ baggage: BaggageContext, into carrier: inout Carrier, using injector: Injector)
72-
where
73-
Injector: InjectorProtocol,
74-
Carrier == Injector.Carrier {}
75-
76-
public func extract<Carrier, Extractor>(_ carrier: Carrier, into baggage: inout BaggageContext, using extractor: Extractor)
77-
where
78-
Extractor: ExtractorProtocol,
79-
Carrier == Extractor.Carrier {}
80-
}

Sources/Instrumentation/InstrumentationSystem.swift

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,27 @@
1414
import Baggage
1515

1616
/// `InstrumentationSystem` is a global facility where the default cross-cutting tool can be configured.
17-
/// It is set up just once in a given program select the desired `Instrument` implementation.
17+
/// It is set up just once in a given program to select the desired `Instrument` implementation.
1818
///
19-
/// - Note: If you need to use more that one cross-cutting tool you can do so by using `MultiplexInstrument`.
19+
/// # Bootstrap multiple Instruments
20+
/// If you need to use more that one cross-cutting tool you can do so by using `MultiplexInstrument`.
21+
///
22+
/// # Access the Instrument
23+
/// There are two ways of getting the bootstrapped instrument.
24+
/// 1. `InstrumentationSystem.instrument`: Returns whatever you passed to `.bootstrap` as an `Instrument`.
25+
/// 2. `InstrumentationSystem.instrument(of: MyInstrument.self)`: Returns the bootstrapped `Instrument` if it's
26+
/// an instance of the given type or the first instance of `MyInstrument` if it's part of a `MultiplexInstrument`.
27+
///
28+
/// ## What getter to use
29+
/// - Default to using `InstrumentationSystem.instrument`
30+
/// - Use `InstrumentationSystem.instrument(of: MyInstrument.self)` only if you need to use specific `MyInstrument` APIs
31+
///
32+
/// Specific instrumentation libraries may also provide their own accessors as extensions, e.g. GreatInstrumentation could provide an
33+
/// `InstrumentationSystem.great` convenience accessor, so prefer using them if available. These accessors should call
34+
/// `.instrument(of: GreatInstrument.self)` under the hood to ensure they work when being used through a `MultiplexInstrument`.
2035
public enum InstrumentationSystem {
2136
private static let lock = ReadWriteLock()
2237
private static var _instrument: Instrument = NoOpInstrument()
23-
private static var _tracer: TracingInstrument?
2438
private static var isInitialized = false
2539

2640
/// Globally select the desired `Instrument` implementation.
@@ -35,36 +49,48 @@ public enum InstrumentationSystem {
3549
you need to use multiple instruments.
3650
"""
3751
)
38-
if let tracer = instrument as? TracingInstrument {
39-
self._tracer = tracer
40-
}
4152
self._instrument = instrument
42-
4353
self.isInitialized = true
4454
}
4555
}
4656

4757
// for our testing we want to allow multiple bootstrapping
4858
internal static func bootstrapInternal(_ instrument: Instrument) {
4959
self.lock.withWriterLock {
50-
if let tracer = instrument as? TracingInstrument {
51-
self._tracer = tracer
52-
}
5360
self._instrument = instrument
5461
}
5562
}
5663

57-
/// Returns the globally configured `Instrument`. Defaults to a no-op `Instrument` if `boostrap` wasn't called before.
64+
/// Returns the globally configured `Instrument`.
65+
///
66+
/// Defaults to a no-op `Instrument` if `boostrap` wasn't called before.
5867
public static var instrument: Instrument {
5968
self.lock.withReaderLock { self._instrument }
6069
}
6170

62-
// FIXME: smarter impl
63-
public static var tracer: TracingInstrument {
71+
/// Get an `Instrument` instance of the given type.
72+
///
73+
/// When using `MultiplexInstrument`, this returns the first instance of the given type stored in the `MultiplexInstrument`.
74+
///
75+
/// - Parameter instrumentType: The type of `Instrument` you want to retrieve an instance for.
76+
/// - Returns: An `Instrument` instance of the given type or `nil` if no `Instrument` of that type has been bootstrapped.
77+
public static func instrument<I>(of instrumentType: I.Type) -> I? where I: Instrument {
78+
self._findInstrument(where: { $0 is I }) as? I
79+
}
80+
81+
}
82+
83+
extension InstrumentationSystem {
84+
/// :nodoc: INTERNAL API: Do Not Use
85+
public static func _findInstrument(where predicate: (Instrument) -> Bool) -> Instrument? {
6486
self.lock.withReaderLock {
65-
let tracer: TracingInstrument? = self._tracer
66-
let res: TracingInstrument = tracer ?? NoOpTracingInstrument()
67-
return res
87+
if let multiplex = self._instrument as? MultiplexInstrument {
88+
return multiplex.firstInstrument(where: predicate)
89+
} else if predicate(self._instrument) {
90+
return self._instrument
91+
} else {
92+
return nil
93+
}
6894
}
6995
}
7096
}

Sources/Instrumentation/MultiplexInstrument.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ public struct MultiplexInstrument {
2727
}
2828
}
2929

30+
extension MultiplexInstrument {
31+
func firstInstrument(where predicate: (Instrument) -> Bool) -> Instrument? {
32+
self.instruments.first(where: predicate)
33+
}
34+
}
35+
3036
extension MultiplexInstrument: Instrument {
3137
public func inject<Carrier, Injector>(
3238
_ baggage: BaggageContext, into carrier: inout Carrier, using injector: Injector
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Distributed Tracing open source project
4+
//
5+
// Copyright (c) 2020 Moritz Lang and the Swift Tracing project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
//
10+
// SPDX-License-Identifier: Apache-2.0
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
import Baggage
15+
16+
/// A "no op" implementation of an `Instrument`.
17+
public struct NoOpInstrument: Instrument {
18+
19+
public init() {}
20+
21+
public func inject<Carrier, Injector>(_ baggage: BaggageContext, into carrier: inout Carrier, using injector: Injector)
22+
where
23+
Injector: InjectorProtocol,
24+
Carrier == Injector.Carrier {}
25+
26+
public func extract<Carrier, Extractor>(_ carrier: Carrier, into baggage: inout BaggageContext, using extractor: Extractor)
27+
where
28+
Extractor: ExtractorProtocol,
29+
Carrier == Extractor.Carrier {}
30+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Distributed Tracing open source project
4+
//
5+
// Copyright (c) 2020 Moritz Lang and the Swift Tracing project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
//
10+
// SPDX-License-Identifier: Apache-2.0
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
import Baggage
15+
import Instrumentation
16+
17+
18+
extension InstrumentationSystem {
19+
20+
/// Get a `TracingInstrument` instance of the given type.
21+
///
22+
/// When using `MultiplexInstrument`, this returns the first instance of the given type stored in the `MultiplexInstrument`.
23+
///
24+
/// Usually tracing libraries will provide their own convenience getter, e.g. CoolTracing could provide `InstrumentationSystem.coolTracer`;
25+
/// if available, prefer using those APIs rather than relying on this general function.
26+
///
27+
/// - Parameter instrumentType: The type of `Instrument` you want to retrieve an instance for.
28+
/// - Returns: An `Instrument` instance of the given type or `nil` if no `Instrument` of that type has been bootstrapped.
29+
public static func tracingInstrument<T>(of instrumentType: T.Type) -> T? where T: TracingInstrument {
30+
self._findInstrument(where: { $0 is T }) as? T
31+
}
32+
33+
/// Returns the `TracingInstrument` bootstrapped as part of the `InstrumentationSystem`.
34+
///
35+
/// If the system was bootstrapped with a `MultiplexInstrument` this function attempts to locate the _first_
36+
/// tracing instrument as passed to the multiplex instrument. If none is found, a `NoOpTracingInstrument` is returned.
37+
///
38+
/// - Returns: A `TracingInstrument` if the system was bootstrapped with one, and `NoOpTracingInstrument` otherwise.
39+
public static var tracingInstrument: TracingInstrument {
40+
(self._findInstrument(where: { $0 is TracingInstrument }) as? TracingInstrument) ?? NoOpTracingInstrument()
41+
}
42+
}

Sources/Instrumentation/Tracing/NoOpTracing.swift renamed to Sources/TracingInstrumentation/NoOpTracingInstrument.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
import Baggage
15+
import Instrumentation
1516

1617
/// No operation TracingInstrument, used when no tracing is required.
1718
public struct NoOpTracingInstrument: TracingInstrument {

0 commit comments

Comments
 (0)