@@ -6,12 +6,12 @@ import Dispatch
66/// See https://prometheus.io/docs/concepts/metric_types/#Histogram
77public struct Buckets : ExpressibleByArrayLiteral {
88 public typealias ArrayLiteralElement = Double
9-
9+
1010 public init ( arrayLiteral elements: Double ... ) {
1111 self . init ( elements)
1212 }
13-
14- fileprivate init ( _ r: [ Double ] ) {
13+
14+ fileprivate init ( _ r: [ Double ] ) {
1515 if r. isEmpty {
1616 self = Buckets . defaultBuckets
1717 return
@@ -24,13 +24,13 @@ public struct Buckets: ExpressibleByArrayLiteral {
2424 assert ( Array ( Set ( r) ) . sorted ( by: < ) == r. sorted ( by: < ) , " Buckets contain duplicate values. " )
2525 self . buckets = r
2626 }
27-
27+
2828 /// The upper bounds
2929 public let buckets : [ Double ]
30-
30+
3131 /// Default buckets used by Histograms
3232 public static let defaultBuckets : Buckets = [ 0.005 , 0.01 , 0.025 , 0.05 , 0.1 , 0.25 , 0.5 , 1 , 2.5 , 5 , 10 ]
33-
33+
3434 /// Create linear buckets used by Histograms
3535 ///
3636 /// - Parameters:
@@ -42,7 +42,7 @@ public struct Buckets: ExpressibleByArrayLiteral {
4242 let arr = ( 0 ..< count) . map { Double ( start) + Double( $0) * Double( width) }
4343 return Buckets ( arr)
4444 }
45-
45+
4646 /// Create exponential buckets used by Histograms
4747 ///
4848 /// - Parameters:
@@ -88,28 +88,28 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
8888 public let name : String
8989 /// Help text of this Histogram, optional
9090 public let help : String ?
91-
91+
9292 /// Type of the metric, used for formatting
9393 public let _type : PromMetricType = . histogram
94-
94+
9595 /// Bucketed values for this Histogram
9696 private var buckets : [ PromCounter < NumType , EmptyLabels > ] = [ ]
97-
97+
9898 /// Buckets used by this Histogram
9999 internal let upperBounds : [ Double ]
100-
100+
101101 /// Labels for this Histogram
102102 internal let labels : Labels
103-
103+
104104 /// Sub Histograms for this Histogram
105105 fileprivate var subHistograms : [ Labels : PromHistogram < NumType , Labels > ] = [ : ]
106-
106+
107107 /// Total value of the Histogram
108108 private let sum : PromCounter < NumType , EmptyLabels >
109-
109+
110110 /// Lock used for thread safety
111111 private let lock : Lock
112-
112+
113113 /// Creates a new Histogram
114114 ///
115115 /// - Parameters:
@@ -125,18 +125,18 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
125125 self . prometheus = p
126126
127127 self . sum = . init( " \( self . name) _sum " , nil , 0 , p)
128-
128+
129129 self . labels = labels
130-
130+
131131 self . upperBounds = buckets. buckets
132-
132+
133133 self . lock = Lock ( )
134-
134+
135135 buckets. buckets. forEach { _ in
136136 self . buckets. append ( . init( " \( name) _bucket " , nil , 0 , p) )
137137 }
138138 }
139-
139+
140140 /// Gets the metric string for this Histogram
141141 ///
142142 /// - Returns:
@@ -147,6 +147,8 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
147147 }
148148
149149 var output = [ String] ( )
150+ // HELP/TYPE + (histogram + subHistograms) * (buckets + sum + count)
151+ output. reserveCapacity ( 2 + ( subHistograms. count + 1 ) * ( buckets. count + 2 ) )
150152
151153 if let help = self . help {
152154 output. append ( " # HELP \( self . name) \( help) " )
@@ -200,11 +202,9 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
200202 /// - value: Value to observe
201203 /// - labels: Labels to attach to the observed value
202204 public func observe( _ value: NumType , _ labels: Labels ? = nil ) {
203- if let labels = labels, type ( of: labels) != type ( of: EmptySummaryLabels ( ) ) {
204- let his : PromHistogram < NumType , Labels > = self . lock. withLock {
205- self . getOrCreateHistogram ( with: labels)
206- }
207- his. observe ( value)
205+ if let labels = labels, type ( of: labels) != type ( of: EmptyHistogramLabels ( ) ) {
206+ self . getOrCreateHistogram ( with: labels)
207+ . observe ( value)
208208 }
209209 self . sum. inc ( value)
210210
@@ -215,7 +215,7 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
215215 }
216216 }
217217 }
218-
218+
219219 /// Time the duration of a closure and observe the resulting time in seconds.
220220 ///
221221 /// - parameters:
@@ -233,14 +233,39 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
233233
234234 /// Helper for histograms & labels
235235 fileprivate func getOrCreateHistogram( with labels: Labels ) -> PromHistogram < NumType , Labels > {
236- let histogram = self . subHistograms [ labels]
237- if let histogram = histogram, histogram. name == self . name, histogram. help == self . help {
236+ let subHistograms = lock. withLock { self . subHistograms }
237+ if let histogram = subHistograms [ labels] {
238+ precondition ( histogram. name == self . name,
239+ """
240+ Somehow got 2 subHistograms with the same data type / labels
241+ but different names: expected \( self . name) , got \( histogram. name)
242+ """ )
243+ precondition ( histogram. help == self . help,
244+ """
245+ Somehow got 2 subHistograms with the same data type / labels
246+ but different help messages: expected \( self . help ?? " nil " ) , got \( histogram. help ?? " nil " )
247+ """ )
238248 return histogram
239249 } else {
240- guard let prometheus = prometheus else { fatalError ( " Lingering Histogram " ) }
241- let newHistogram = PromHistogram ( self . name, self . help, labels, Buckets ( self . upperBounds) , prometheus)
242- self . subHistograms [ labels] = newHistogram
243- return newHistogram
250+ return lock. withLock {
251+ if let histogram = subHistograms [ labels] {
252+ precondition ( histogram. name == self . name,
253+ """
254+ Somehow got 2 subHistograms with the same data type / labels
255+ but different names: expected \( self . name) , got \( histogram. name)
256+ """ )
257+ precondition ( histogram. help == self . help,
258+ """
259+ Somehow got 2 subHistograms with the same data type / labels
260+ but different help messages: expected \( self . help ?? " nil " ) , got \( histogram. help ?? " nil " )
261+ """ )
262+ return histogram
263+ }
264+ guard let prometheus = prometheus else { fatalError ( " Lingering Histogram " ) }
265+ let newHistogram = PromHistogram ( self . name, self . help, labels, Buckets ( self . upperBounds) , prometheus)
266+ self . subHistograms [ labels] = newHistogram
267+ return newHistogram
268+ }
244269 }
245270 }
246271}
0 commit comments