@@ -83,7 +83,7 @@ extension HistogramLabels {
8383public class PromHistogram < NumType: DoubleRepresentable , Labels: HistogramLabels > : PromMetric , PrometheusHandled {
8484 /// Prometheus instance that created this Histogram
8585 internal weak var prometheus : PrometheusClient ?
86-
86+
8787 /// Name of this Histogram, required
8888 public let name : String
8989 /// Help text of this Histogram, optional
@@ -99,10 +99,10 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
9999 internal let upperBounds : [ Double ]
100100
101101 /// Labels for this Histogram
102- internal private ( set ) var labels : Labels
102+ internal let labels : Labels
103103
104104 /// Sub Histograms for this Histogram
105- fileprivate var subHistograms : [ PromHistogram < NumType , Labels > ] = [ ]
105+ fileprivate var subHistograms : [ Labels : PromHistogram < NumType , Labels > ] = [ : ]
106106
107107 /// Total value of the Histogram
108108 private let sum : PromCounter < NumType , EmptyLabels >
@@ -121,9 +121,9 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
121121 internal init ( _ name: String , _ help: String ? = nil , _ labels: Labels = Labels ( ) , _ buckets: Buckets = . defaultBuckets, _ p: PrometheusClient ) {
122122 self . name = name
123123 self . help = help
124-
124+
125125 self . prometheus = p
126-
126+
127127 self . sum = . init( " \( self . name) _sum " , nil , 0 , p)
128128
129129 self . labels = labels
@@ -142,68 +142,76 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
142142 /// - Returns:
143143 /// Newline separated Prometheus formatted metric string
144144 public func collect( ) -> String {
145- return self . lock. withLock {
146- var output = [ String] ( )
147-
148- if let help = self . help {
149- output. append ( " # HELP \( self . name) \( help) " )
150- }
151- output. append ( " # TYPE \( self . name) \( self . _type) " )
152-
153- var acc : NumType = 0
154- for (i, bound) in self . upperBounds. enumerated ( ) {
155- acc += self . buckets [ i] . get ( )
156- self . labels. le = bound. description
157- let labelsString = encodeLabels ( self . labels)
158- output. append ( " \( self . name) _bucket \( labelsString) \( acc) " )
159- }
160-
161- let labelsString = encodeLabels ( self . labels, [ " le " ] )
162- output. append ( " \( self . name) _count \( labelsString) \( acc) " )
163-
164- output. append ( " \( self . name) _sum \( labelsString) \( self . sum. get ( ) ) " )
165-
166- self . subHistograms. forEach { subHistogram in
167- var acc : NumType = 0
168- for (i, bound) in subHistogram. upperBounds. enumerated ( ) {
169- acc += subHistogram. buckets [ i] . get ( )
170- subHistogram. labels. le = bound. description
171- let labelsString = encodeLabels ( subHistogram. labels)
172- output. append ( " \( subHistogram. name) _bucket \( labelsString) \( acc) " )
173- }
174-
175- let labelsString = encodeLabels ( subHistogram. labels, [ " le " ] )
176- output. append ( " \( subHistogram. name) _count \( labelsString) \( acc) " )
177-
178- output. append ( " \( subHistogram. name) _sum \( labelsString) \( subHistogram. sum. get ( ) ) " )
179-
180- subHistogram. labels. le = " "
145+ let ( buckets, subHistograms, labels) = self . lock. withLock {
146+ ( self . buckets, self . subHistograms, self . labels)
147+ }
148+
149+ var output = [ String] ( )
150+
151+ if let help = self . help {
152+ output. append ( " # HELP \( self . name) \( help) " )
153+ }
154+ output. append ( " # TYPE \( self . name) \( self . _type) " )
155+ collectBuckets ( buckets: buckets,
156+ upperBounds: self . upperBounds,
157+ name: self . name,
158+ labels: labels,
159+ sum: self . sum. get ( ) ,
160+ into: & output)
161+
162+ subHistograms. forEach { subHistogram in
163+ let ( subHistogramBuckets, subHistogramLabels) = self . lock. withLock {
164+ ( subHistogram. value. buckets, subHistogram. value. labels)
181165 }
182-
183- self . labels. le = " "
184-
185- return output. joined ( separator: " \n " )
166+ collectBuckets ( buckets: subHistogramBuckets,
167+ upperBounds: subHistogram. value. upperBounds,
168+ name: subHistogram. value. name,
169+ labels: subHistogramLabels,
170+ sum: subHistogram. value. sum. get ( ) ,
171+ into: & output)
186172 }
173+ return output. joined ( separator: " \n " )
187174 }
188-
175+
176+ private func collectBuckets( buckets: [ PromCounter < NumType , EmptyLabels > ] ,
177+ upperBounds: [ Double ] ,
178+ name: String ,
179+ labels: Labels ,
180+ sum: NumType ,
181+ into output: inout [ String ] ) {
182+ var labels = labels
183+ var acc : NumType = 0
184+ for (i, bound) in upperBounds. enumerated ( ) {
185+ acc += buckets [ i] . get ( )
186+ labels. le = bound. description
187+ let labelsString = encodeLabels ( labels)
188+ output. append ( " \( name) _bucket \( labelsString) \( acc) " )
189+ }
190+
191+ let labelsString = encodeLabels ( labels, [ " le " ] )
192+ output. append ( " \( name) _count \( labelsString) \( acc) " )
193+
194+ output. append ( " \( name) _sum \( labelsString) \( sum) " )
195+ }
196+
189197 /// Observe a value
190198 ///
191199 /// - Parameters:
192200 /// - value: Value to observe
193201 /// - labels: Labels to attach to the observed value
194202 public func observe( _ value: NumType , _ labels: Labels ? = nil ) {
195- self . lock. withLock {
196- if let labels = labels, type ( of: labels) != type ( of: EmptySummaryLabels ( ) ) {
197- guard let his = self . prometheus? . getOrCreateHistogram ( with: labels, for: self ) else { fatalError ( " Lingering Histogram " ) }
198- his. observe ( value)
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)
199206 }
200- self . sum. inc ( value)
201-
202- for (i, bound) in self . upperBounds. enumerated ( ) {
203- if bound >= value. doubleValue {
204- self . buckets [ i] . inc ( )
205- return
206- }
207+ his. observe ( value)
208+ }
209+ self . sum. inc ( value)
210+
211+ for (i, bound) in self . upperBounds. enumerated ( ) {
212+ if bound >= value. doubleValue {
213+ self . buckets [ i] . inc ( )
214+ return
207215 }
208216 }
209217 }
@@ -222,21 +230,16 @@ public class PromHistogram<NumType: DoubleRepresentable, Labels: HistogramLabels
222230 }
223231 return try body ( )
224232 }
225- }
226233
227- extension PrometheusClient {
228234 /// Helper for histograms & labels
229- fileprivate func getOrCreateHistogram< T: Numeric , U: HistogramLabels > ( with labels: U , for histogram: PromHistogram < T , U > ) -> PromHistogram < T , U > {
230- let histograms = histogram. subHistograms. filter { ( metric) -> Bool in
231- guard metric. name == histogram. name, metric. help == histogram. help, metric. labels == labels else { return false }
232- return true
233- }
234- if histograms. count > 2 { fatalError ( " Somehow got 2 histograms with the same data type " ) }
235- if let histogram = histograms. first {
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 {
236238 return histogram
237239 } else {
238- let newHistogram = PromHistogram < T , U > ( histogram. name, histogram. help, labels, Buckets ( histogram. upperBounds) , self )
239- histogram. subHistograms. append ( newHistogram)
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
240243 return newHistogram
241244 }
242245 }
0 commit comments