Skip to content

Commit 01b4acc

Browse files
authored
Get metric promises (#12)
* Update to promises * Minor cleanup * NIO 2 * Byte Buffers & no promises * Move ByteBuffer methods to extensions and (temp) remove Swift 4 tests * NIO Bump & docs * Add some helpers & update test wording
1 parent 955b9d4 commit 01b4acc

File tree

8 files changed

+108
-35
lines changed

8 files changed

+108
-35
lines changed

Package.resolved

Lines changed: 2 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ let package = Package(
1414
],
1515
dependencies: [
1616
.package(url: "https://github.com/apple/swift-metrics.git", from: "1.0.0"),
17-
.package(url: "https://github.com/apple/swift-nio.git", Version("1.0.0") ..< Version("3.0.0")),
17+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
1818
],
1919
targets: [
2020
.target(
2121
name: "Prometheus",
22-
dependencies: ["CoreMetrics", "NIOConcurrencyHelpers"]),
22+
dependencies: ["CoreMetrics", "NIOConcurrencyHelpers", "NIO"]),
2323
.target(
2424
name: "PrometheusExample",
2525
dependencies: ["Prometheus", "Metrics"]),

Sources/Prometheus/MetricTypes/Counter.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ public class PromCounter<NumType: Numeric, Labels: MetricLabels>: PromMetric, Pr
6767
}
6868
}
6969

70-
7170
/// Increments the Counter
7271
///
7372
/// - Parameters:

Sources/Prometheus/MetricTypes/PromMetric.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import NIO
2+
13
/// Different types of metrics supported by SwiftPrometheus
24
public enum PromMetricType: String {
35
/// See `PromCounter`
@@ -34,6 +36,16 @@ public protocol PromMetric {
3436
func collect() -> String
3537
}
3638

39+
extension PromMetric {
40+
/// Helper method to record metrics into a `ByteBuffer` directly
41+
///
42+
/// - Parameters:
43+
/// - buffer: `ByteBuffer` to collect into
44+
func collect(into buffer: inout ByteBuffer) {
45+
buffer.writeString(collect())
46+
}
47+
}
48+
3749
/// Adding a prometheus instance to all metrics
3850
internal protocol PrometheusHandled {
3951
/// Promtheus client handling this metric

Sources/Prometheus/Prometheus.swift

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import NIOConcurrencyHelpers
2+
import NIO
23

34
/// Prometheus class
45
///
@@ -22,14 +23,47 @@ public class PrometheusClient {
2223
self.lock = Lock()
2324
}
2425

26+
// MARK: - Collection
27+
2528
/// Creates prometheus formatted metrics
2629
///
27-
/// - Returns: Newline separated string with metrics for all Metric Trackers of this Prometheus instance
28-
public func collect() -> String {
29-
return self.lock.withLock {
30-
return self.metrics.map { $0.collect() }.joined(separator: "\n")
30+
/// - Parameters:
31+
/// - succeed: Closure that will be called with a newline separated string with metrics for all Metrics this PrometheusClient handles
32+
public func collect(_ succeed: (String) -> ()) {
33+
self.lock.withLock {
34+
succeed(self.metrics.map { $0.collect() }.joined(separator: "\n"))
35+
}
36+
}
37+
38+
/// Creates prometheus formatted metrics
39+
///
40+
/// - Parameters:
41+
/// - promise: Promise that will succeed with a newline separated string with metrics for all Metrics this PrometheusClient handles
42+
public func collect(into promise: EventLoopPromise<String>) {
43+
collect(promise.succeed)
44+
}
45+
46+
/// Creates prometheus formatted metrics
47+
///
48+
/// - Parameters:
49+
/// - succeed: Closure that will be called with a `ByteBuffer` containing a newline separated string with metrics for all Metrics this PrometheusClient handles
50+
public func collect(_ succeed: (ByteBuffer) -> ()) {
51+
self.lock.withLock {
52+
var buffer = ByteBufferAllocator().buffer(capacity: 0)
53+
self.metrics.forEach {
54+
$0.collect(into: &buffer)
55+
}
56+
succeed(buffer)
3157
}
3258
}
59+
60+
/// Creates prometheus formatted metrics
61+
///
62+
/// - Parameters:
63+
/// - promise: Promise that will succeed with a `ByteBuffer` containing a newline separated string with metrics for all Metrics this PrometheusClient handles
64+
public func collect(into promise: EventLoopPromise<ByteBuffer>) {
65+
collect(promise.succeed)
66+
}
3367

3468
// MARK: - Metric Access
3569

Sources/PrometheusExample/main.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Prometheus
22
import Metrics
3+
import NIO
34

45
let myProm = PrometheusClient()
56

@@ -111,5 +112,11 @@ for _ in 0...Int.random(in: 100...1000) {
111112
summary.observe(Double.random(in: 0...10000), SummaryThing("/test"))
112113
}
113114

114-
let metrics = try! MetricsSystem.prometheus().collect()
115-
print(metrics)
115+
let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1)
116+
let prom = elg.next().makePromise(of: String.self)
117+
118+
prom.futureResult.whenSuccess {
119+
print($0)
120+
}
121+
122+
try! MetricsSystem.prometheus().collect(prom.succeed)

Tests/SwiftPrometheusTests/PrometheusMetricsTests.swift

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
11
import XCTest
2+
import NIO
23
@testable import Prometheus
34
@testable import CoreMetrics
45

56
final class PrometheusMetricsTests: XCTestCase {
67

78
var prom: PrometheusClient!
9+
var group: EventLoopGroup!
10+
var eventLoop: EventLoop {
11+
return group.next()
12+
}
813

914
override func setUp() {
1015
self.prom = PrometheusClient()
16+
self.group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
1117
MetricsSystem.bootstrapInternal(prom)
1218
}
1319

1420
override func tearDown() {
1521
self.prom = nil
22+
try! self.group.syncShutdownGracefully()
1623
}
1724

1825
func testCounter() {
1926
let counter = Counter(label: "my_counter")
2027
counter.increment(by: 10)
2128
let counterTwo = Counter(label: "my_counter", dimensions: [("myValue", "labels")])
2229
counterTwo.increment(by: 10)
23-
24-
XCTAssertEqual(prom.collect(), """
30+
31+
let promise = self.eventLoop.makePromise(of: String.self)
32+
prom.collect(promise.succeed)
33+
34+
XCTAssertEqual(try! promise.futureResult.wait(), """
2535
# TYPE my_counter counter
2636
my_counter 10
2737
my_counter{myValue=\"labels\"} 10
@@ -38,7 +48,10 @@ final class PrometheusMetricsTests: XCTestCase {
3848
let gaugeTwo = Gauge(label: "my_gauge", dimensions: [("myValue", "labels")])
3949
gaugeTwo.record(10)
4050

41-
XCTAssertEqual(prom.collect(), """
51+
let promise = self.eventLoop.makePromise(of: String.self)
52+
prom.collect(promise.succeed)
53+
54+
XCTAssertEqual(try! promise.futureResult.wait(), """
4255
# TYPE my_gauge gauge
4356
my_gauge 20.0
4457
my_gauge{myValue=\"labels\"} 10.0
@@ -54,7 +67,10 @@ final class PrometheusMetricsTests: XCTestCase {
5467
let recorderTwo = Recorder(label: "my_histogram", dimensions: [("myValue", "labels")])
5568
recorderTwo.record(3)
5669

57-
XCTAssertEqual(prom.collect(), """
70+
let promise = self.eventLoop.makePromise(of: String.self)
71+
prom.collect(promise.succeed)
72+
73+
XCTAssertEqual(try! promise.futureResult.wait(), """
5874
# TYPE my_histogram histogram
5975
my_histogram_bucket{le="0.005"} 0.0
6076
my_histogram_bucket{le="0.01"} 0.0
@@ -104,7 +120,10 @@ final class PrometheusMetricsTests: XCTestCase {
104120
let summaryTwo = Timer(label: "my_summary", dimensions: [("myValue", "labels")])
105121
summaryTwo.recordNanoseconds(123)
106122

107-
XCTAssertEqual(prom.collect(), """
123+
let promise = self.eventLoop.makePromise(of: String.self)
124+
prom.collect(promise.succeed)
125+
126+
XCTAssertEqual(try! promise.futureResult.wait(), """
108127
# TYPE my_summary summary
109128
my_summary{quantile="0.01"} 1.0
110129
my_summary{quantile="0.05"} 1.0
@@ -131,7 +150,27 @@ final class PrometheusMetricsTests: XCTestCase {
131150
let counter = Counter(label: "my_counter")
132151
counter.increment()
133152
counter.destroy()
134-
XCTAssertEqual(prom.collect(), "")
153+
let promise = self.eventLoop.makePromise(of: String.self)
154+
prom.collect(promise.succeed)
155+
156+
XCTAssertEqual(try! promise.futureResult.wait(), "")
157+
}
158+
159+
func testBuffer() {
160+
let counter = Counter(label: "my_counter")
161+
counter.increment(by: 10)
162+
let counterTwo = Counter(label: "my_counter", dimensions: [("myValue", "labels")])
163+
counterTwo.increment(by: 10)
164+
165+
let promise = self.eventLoop.makePromise(of: ByteBuffer.self)
166+
prom.collect(promise.succeed)
167+
var buffer = try! promise.futureResult.wait()
168+
169+
XCTAssertEqual(buffer.readString(length: buffer.readableBytes), """
170+
# TYPE my_counter counter
171+
my_counter 10
172+
my_counter{myValue=\"labels\"} 10
173+
""")
135174
}
136175
}
137176

circle.yml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
version: 2
22

33
jobs:
4-
swift4:
5-
docker:
6-
- image: swift:4.2
7-
steps:
8-
- checkout
9-
- run: apt-get update; apt-get install -y libssl-dev zlib1g-dev
10-
- run: swift build
11-
- run: swift test
124
swift5:
135
docker:
146
- image: swift:5.0
@@ -39,5 +31,4 @@ workflows:
3931
jobs:
4032
- bionic
4133
- bionic-release
42-
- swift4
4334
- swift5

0 commit comments

Comments
 (0)