Skip to content

Commit 3d5d06d

Browse files
committed
Make summary label-able
1 parent 913a256 commit 3d5d06d

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

Sources/Prometheus/MetricTypes/Summary.swift

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ public class Summary<NumType: DoubleRepresentable, Labels: SummaryLabels>: Metri
1717
public let name: String
1818
public let help: String?
1919

20-
private var labels: Labels
20+
internal private(set) var labels: Labels
2121

2222
private let sum: Counter<NumType, EmptyCodable>
2323

2424
private let count: Counter<NumType, EmptyCodable>
2525

2626
private var values: [NumType] = []
2727

28-
private var quantiles: [Double]
28+
internal let quantiles: [Double]
2929

3030
internal init(_ name: String, _ help: String? = nil, _ quantiles: [Double] = defaultQuantiles, _ labels: Labels = Labels(), _ p: Prometheus) {
3131
self.name = name
@@ -45,10 +45,12 @@ public class Summary<NumType: DoubleRepresentable, Labels: SummaryLabels>: Metri
4545
public func getMetric() -> String {
4646
var output = [String]()
4747

48-
if let help = help {
49-
output.append("# HELP \(name) \(help)")
48+
if self.labels == Labels() {
49+
if let help = help {
50+
output.append("# HELP \(name) \(help)")
51+
}
52+
output.append("# TYPE \(name) summary")
5053
}
51-
output.append("# TYPE \(name) summary")
5254

5355
calculateQuantiles(quantiles: quantiles, values: values.map { $0.doubleValue }).sorted { $0.key < $1.key }.forEach { (arg) in
5456
let (q, v) = arg
@@ -60,17 +62,40 @@ public class Summary<NumType: DoubleRepresentable, Labels: SummaryLabels>: Metri
6062
let labelsString = encodeLabels(self.labels, ["quantile"])
6163
output.append("\(name)_count\(labelsString) \(count.get())")
6264
output.append("\(name)_sum\(labelsString) \(sum.get())")
63-
65+
66+
self.labels.quantile = ""
67+
6468
return output.joined(separator: "\n")
6569
}
6670

67-
public func observe(_ value: NumType) {
71+
public func observe(_ value: NumType, _ labels: Labels? = nil) {
72+
if let labels = labels, type(of: labels) != type(of: EmptySummaryCodable()) {
73+
let sum = self.prometheus.getOrCreateSummary(withLabels: labels, forSummary: self)
74+
sum.observe(value)
75+
return
76+
}
6877
self.count.inc(1)
6978
self.sum.inc(value)
7079
self.values.append(value)
7180
}
7281
}
7382

83+
extension Prometheus {
84+
fileprivate func getOrCreateSummary<T: Numeric, U: SummaryLabels>(withLabels labels: U, forSummary sum: Summary<T, U>) -> Summary<T, U> {
85+
let summary = metrics.filter { (metric) -> Bool in
86+
guard let metric = metric as? Summary<T, U> else { return false }
87+
guard metric.name == sum.name, metric.help == sum.help, metric.labels == labels else { return false }
88+
return true
89+
} as? [Summary<T, U>] ?? []
90+
if summary.count > 2 { fatalError("Somehow got 2 summaries with the same data type") }
91+
if let summary = summary.first {
92+
return summary
93+
} else {
94+
return createSummary(forType: T.self, named: sum.name, helpText: sum.help, quantiles: sum.quantiles, labels: labels)
95+
}
96+
}
97+
}
98+
7499
func calculateQuantiles(quantiles: [Double], values: [Double]) -> [Double: Double] {
75100
let values = values.sorted()
76101
var quantilesMap: [Double: Double] = [:]
@@ -81,6 +106,9 @@ func calculateQuantiles(quantiles: [Double], values: [Double]) -> [Double: Doubl
81106
}
82107

83108
func quantile(_ q: Double, _ values: [Double]) -> Double {
109+
if values.count == 0 {
110+
return 0
111+
}
84112
if values.count == 1 {
85113
return values[0]
86114
}

Sources/PrometheusExample/main.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,27 @@ for _ in 0...Int.random(in: 10...50) {
2121
histogram.observe(Double.random(in: 0...1))
2222
}
2323

24-
let summary = Prometheus.shared.createSummary(forType: Double.self, named: "my_summary", helpText: "Just a summary")
24+
struct SummaryThing: SummaryLabels {
25+
var quantile: String = ""
26+
let route: String
27+
28+
init() {
29+
self.route = "*"
30+
}
31+
32+
init(_ route: String) {
33+
self.route = route
34+
}
35+
}
36+
37+
let summary = Prometheus.shared.createSummary(forType: Double.self, named: "my_summary", helpText: "Just a summary", labels: SummaryThing())
2538

2639
for _ in 0...Int.random(in: 100...1000) {
2740
summary.observe(Double.random(in: 0...10000))
2841
}
2942

43+
for _ in 0...Int.random(in: 100...1000) {
44+
summary.observe(Double.random(in: 0...10000), SummaryThing("/test"))
45+
}
46+
3047
print(Prometheus.shared.getMetrics())

0 commit comments

Comments
 (0)