@@ -24,56 +24,78 @@ import ServiceContextModule
2424/// ``instrument``: Returns whatever you passed to ``bootstrap(_:)`` as an ``Instrument``.
2525@available ( macOS 10 . 15 , iOS 13 , tvOS 13 , watchOS 6 , * ) // for TaskLocal ServiceContext
2626public enum InstrumentationSystem {
27- private static let lock = ReadWriteLock ( )
28- private static var _instrument : Instrument = NoOpInstrument ( )
29- private static var isInitialized = false
27+ /// Marked as @unchecked Sendable due to the synchronization being
28+ /// performed manually using locks.
29+ private final class Storage : @unchecked Sendable {
30+ private let lock = ReadWriteLock ( )
31+ private var _instrument : Instrument = NoOpInstrument ( )
32+ private var _isInitialized = false
33+
34+ func bootstrap( _ instrument: Instrument ) {
35+ self . lock. withWriterLock {
36+ precondition (
37+ !self . _isInitialized, """
38+ InstrumentationSystem can only be initialized once per process. Consider using MultiplexInstrument if
39+ you need to use multiple instruments.
40+ """
41+ )
42+ self . _instrument = instrument
43+ self . _isInitialized = true
44+ }
45+ }
46+
47+ func bootstrapInternal( _ instrument: Instrument ? ) {
48+ self . lock. withWriterLock {
49+ self . _instrument = instrument ?? NoOpInstrument ( )
50+ }
51+ }
52+
53+ var instrument : Instrument {
54+ self . lock. withReaderLock { self . _instrument }
55+ }
56+
57+ func _findInstrument( where predicate: ( Instrument ) -> Bool ) -> Instrument ? {
58+ self . lock. withReaderLock {
59+ if let multiplex = self . _instrument as? MultiplexInstrument {
60+ return multiplex. firstInstrument ( where: predicate)
61+ } else if predicate ( self . _instrument) {
62+ return self . _instrument
63+ } else {
64+ return nil
65+ }
66+ }
67+ }
68+ }
69+
70+ private static let shared = Storage ( )
3071
3172 /// Globally select the desired ``Instrument`` implementation.
3273 ///
3374 /// - Parameter instrument: The ``Instrument`` you want to share globally within your system.
3475 /// - Warning: Do not call this method more than once. This will lead to a crash.
3576 public static func bootstrap( _ instrument: Instrument ) {
36- self . lock. withWriterLock {
37- precondition (
38- !self . isInitialized, """
39- InstrumentationSystem can only be initialized once per process. Consider using MultiplexInstrument if
40- you need to use multiple instruments.
41- """
42- )
43- self . _instrument = instrument
44- self . isInitialized = true
45- }
77+ self . shared. bootstrap ( instrument)
4678 }
4779
4880 /// For testing scenarios one may want to set instruments multiple times, rather than the set-once semantics enforced by ``bootstrap(_:)``.
4981 ///
5082 /// - Parameter instrument: the instrument to boostrap the system with, if `nil` the ``NoOpInstrument`` is bootstrapped.
5183 internal static func bootstrapInternal( _ instrument: Instrument ? ) {
52- self . lock. withWriterLock {
53- self . _instrument = instrument ?? NoOpInstrument ( )
54- }
84+ self . shared. bootstrapInternal ( instrument)
5585 }
5686
5787 /// Returns the globally configured ``Instrument``.
5888 ///
5989 /// Defaults to a no-op ``Instrument`` if ``bootstrap(_:)`` wasn't called before.
6090 public static var instrument : Instrument {
61- self . lock . withReaderLock { self . _instrument }
91+ shared . instrument
6292 }
6393}
6494
6595@available ( macOS 10 . 15 , iOS 13 , tvOS 13 , watchOS 6 , * ) // for TaskLocal ServiceContext
6696extension InstrumentationSystem {
6797 /// INTERNAL API: Do Not Use
6898 public static func _findInstrument( where predicate: ( Instrument ) -> Bool ) -> Instrument ? {
69- self . lock. withReaderLock {
70- if let multiplex = self . _instrument as? MultiplexInstrument {
71- return multiplex. firstInstrument ( where: predicate)
72- } else if predicate ( self . _instrument) {
73- return self . _instrument
74- } else {
75- return nil
76- }
77- }
99+ self . shared. _findInstrument ( where: predicate)
78100 }
79101}
0 commit comments