@@ -6,12 +6,12 @@ import Dispatch
6
6
/// See https://prometheus.io/docs/concepts/metric_types/#Histogram
7
7
public struct Buckets : ExpressibleByArrayLiteral {
8
8
public typealias ArrayLiteralElement = Double
9
-
9
+
10
10
public init ( arrayLiteral elements: Double ... ) {
11
11
self . init ( elements)
12
12
}
13
-
14
- fileprivate init ( _ r: [ Double ] ) {
13
+
14
+ fileprivate init ( _ r: [ Double ] ) {
15
15
if r. isEmpty {
16
16
self = Buckets . defaultBuckets
17
17
return
@@ -24,13 +24,13 @@ public struct Buckets: ExpressibleByArrayLiteral {
24
24
assert ( Array ( Set ( r) ) . sorted ( by: < ) == r. sorted ( by: < ) , " Buckets contain duplicate values. " )
25
25
self . buckets = r
26
26
}
27
-
27
+
28
28
/// The upper bounds
29
29
public let buckets : [ Double ]
30
-
30
+
31
31
/// Default buckets used by Histograms
32
32
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
+
34
34
/// Create linear buckets used by Histograms
35
35
///
36
36
/// - Parameters:
@@ -42,7 +42,7 @@ public struct Buckets: ExpressibleByArrayLiteral {
42
42
let arr = ( 0 ..< count) . map { Double ( start) + Double( $0) * Double( width) }
43
43
return Buckets ( arr)
44
44
}
45
-
45
+
46
46
/// Create exponential buckets used by Histograms
47
47
///
48
48
/// - Parameters:
@@ -88,28 +88,28 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
88
88
public let name : String
89
89
/// Help text of this Histogram, optional
90
90
public let help : String ?
91
-
91
+
92
92
/// Type of the metric, used for formatting
93
93
public let _type : PromMetricType = . histogram
94
-
94
+
95
95
/// Bucketed values for this Histogram
96
96
private var buckets : [ PromCounter < NumType , EmptyLabels > ] = [ ]
97
-
97
+
98
98
/// Buckets used by this Histogram
99
99
internal let upperBounds : [ Double ]
100
-
100
+
101
101
/// Labels for this Histogram
102
102
internal let labels : Labels
103
-
103
+
104
104
/// Sub Histograms for this Histogram
105
105
fileprivate var subHistograms : [ Labels : PromHistogram < NumType , Labels > ] = [ : ]
106
-
106
+
107
107
/// Total value of the Histogram
108
108
private let sum : PromCounter < NumType , EmptyLabels >
109
-
109
+
110
110
/// Lock used for thread safety
111
111
private let lock : Lock
112
-
112
+
113
113
/// Creates a new Histogram
114
114
///
115
115
/// - Parameters:
@@ -125,18 +125,18 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
125
125
self . prometheus = p
126
126
127
127
self . sum = . init( " \( self . name) _sum " , nil , 0 , p)
128
-
128
+
129
129
self . labels = labels
130
-
130
+
131
131
self . upperBounds = buckets. buckets
132
-
132
+
133
133
self . lock = Lock ( )
134
-
134
+
135
135
buckets. buckets. forEach { _ in
136
136
self . buckets. append ( . init( " \( name) _bucket " , nil , 0 , p) )
137
137
}
138
138
}
139
-
139
+
140
140
/// Gets the metric string for this Histogram
141
141
///
142
142
/// - Returns:
@@ -147,6 +147,8 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
147
147
}
148
148
149
149
var output = [ String] ( )
150
+ // HELP/TYPE + (histogram + subHistograms) * (buckets + sum + count)
151
+ output. reserveCapacity ( 2 + ( subHistograms. count + 1 ) * ( buckets. count + 2 ) )
150
152
151
153
if let help = self . help {
152
154
output. append ( " # HELP \( self . name) \( help) " )
@@ -200,11 +202,9 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
200
202
/// - value: Value to observe
201
203
/// - labels: Labels to attach to the observed value
202
204
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)
208
208
}
209
209
self . sum. inc ( value)
210
210
@@ -215,7 +215,7 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
215
215
}
216
216
}
217
217
}
218
-
218
+
219
219
/// Time the duration of a closure and observe the resulting time in seconds.
220
220
///
221
221
/// - parameters:
@@ -233,14 +233,39 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
233
233
234
234
/// Helper for histograms & labels
235
235
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
+ """ )
238
248
return histogram
239
249
} 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
+ }
244
269
}
245
270
}
246
271
}
0 commit comments