Skip to content

Commit 3fefeda

Browse files
MrLotUtomerd
authored andcommitted
TimeUnits (#42)
motivation: some metrics backend prefer to be given a hint about the preferred display unit (seconds, milliseconds, etc) to drive the ux changes: add a `preferedUnit` to TimerHandler (and `TimeUnits`) to capture the prefer display unit
1 parent 853893b commit 3fefeda

File tree

5 files changed

+81
-0
lines changed

5 files changed

+81
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
.xcode
66
.SourceKitten
77
*.orig
8+
.swiftpm

Sources/CoreMetrics/Metrics.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ public class Gauge: Recorder {
172172
}
173173
}
174174

175+
public enum TimeUnit {
176+
case nanoseconds, milliseconds, seconds, minutes, hours, days
177+
}
178+
175179
public extension Timer {
176180
/// Create a new `Timer`.
177181
///
@@ -183,6 +187,18 @@ public extension Timer {
183187
self.init(label: label, dimensions: dimensions, handler: handler)
184188
}
185189

190+
/// Create a new `Timer`.
191+
///
192+
/// - parameters:
193+
/// - label: The label for the `Timer`.
194+
/// - dimensions: The dimensions for the `Timer`.
195+
/// - displayUnit: A hint to the backend responsible for presenting the data of the preferred display unit. This is not guaranteed to be supported by all backends.
196+
convenience init(label: String, dimensions: [(String, String)] = [], preferredDisplayUnit displayUnit: TimeUnit) {
197+
let handler = MetricsSystem.factory.makeTimer(label: label, dimensions: dimensions)
198+
handler.preferDisplayUnit(displayUnit)
199+
self.init(label: label, dimensions: dimensions, handler: handler)
200+
}
201+
186202
/// Signal the underlying metrics library that this timer will never be updated again.
187203
/// In response the library MAY decide to eagerly release any resources held by this `Timer`.
188204
@inlinable
@@ -483,6 +499,18 @@ public protocol TimerHandler: AnyObject {
483499
/// - parameters:
484500
/// - value: Duration to record.
485501
func recordNanoseconds(_ duration: Int64)
502+
503+
/// Set the preferred display unit for this TimerHandler.
504+
///
505+
/// - parameters:
506+
/// - unit: A hint to the backend responsible for presenting the data of the preferred display unit. This is not guaranteed to be supported by all backends.
507+
func preferDisplayUnit(_ unit: TimeUnit)
508+
}
509+
510+
extension TimerHandler {
511+
public func preferDisplayUnit(_: TimeUnit) {
512+
// NOOP
513+
}
486514
}
487515

488516
// MARK: Predefined Metrics Handlers

Tests/MetricsTests/MetricsTests+XCTest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ extension MetricsExtensionsTests {
2828
("testTimerBlock", testTimerBlock),
2929
("testTimerWithTimeInterval", testTimerWithTimeInterval),
3030
("testTimerWithDispatchTime", testTimerWithDispatchTime),
31+
("testTimerUnits", testTimerUnits),
3132
]
3233
}
3334
}

Tests/MetricsTests/MetricsTests.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,32 @@ class MetricsExtensionsTests: XCTestCase {
7777
XCTAssertEqual(testTimer.values.count, 5, "expected number of entries to match")
7878
XCTAssertEqual(testTimer.values[4].1, 0, "expected value to match")
7979
}
80+
81+
func testTimerUnits() throws {
82+
let metrics = TestMetrics()
83+
MetricsSystem.bootstrapInternal(metrics)
84+
85+
let name = "timer-\(NSUUID().uuidString)"
86+
let value = Int64.random(in: 0 ... 1000)
87+
88+
let timer = Timer(label: name)
89+
timer.recordNanoseconds(value)
90+
91+
let testTimer = timer.handler as! TestTimer
92+
XCTAssertEqual(testTimer.values.count, 1, "expected number of entries to match")
93+
XCTAssertEqual(testTimer.values.first!.1, value, "expected value to match")
94+
XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored")
95+
96+
let secondsName = "timer-seconds-\(NSUUID().uuidString)"
97+
let secondsValue = Int64.random(in: 0 ... 1000)
98+
let secondsTimer = Timer(label: secondsName, preferredDisplayUnit: .seconds)
99+
secondsTimer.recordSeconds(secondsValue)
100+
101+
let testSecondsTimer = secondsTimer.handler as! TestTimer
102+
XCTAssertEqual(testSecondsTimer.values.count, 1, "expected number of entries to match")
103+
XCTAssertEqual(testSecondsTimer.retriveValueInPreferredUnit(atIndex: 0), secondsValue, "expected value to match")
104+
XCTAssertEqual(metrics.timers.count, 2, "timer should have been stored")
105+
}
80106
}
81107

82108
// https://bugs.swift.org/browse/SR-6310

Tests/MetricsTests/TestMetrics.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ internal class TestRecorder: RecorderHandler, Equatable {
135135
internal class TestTimer: TimerHandler, Equatable {
136136
let id: String
137137
let label: String
138+
var displayUnit: TimeUnit?
138139
let dimensions: [(String, String)]
139140

140141
let lock = NSLock()
@@ -143,9 +144,33 @@ internal class TestTimer: TimerHandler, Equatable {
143144
init(label: String, dimensions: [(String, String)]) {
144145
self.id = NSUUID().uuidString
145146
self.label = label
147+
self.displayUnit = nil
146148
self.dimensions = dimensions
147149
}
148150

151+
func preferDisplayUnit(_ unit: TimeUnit) {
152+
self.lock.withLock {
153+
self.displayUnit = unit
154+
}
155+
}
156+
157+
func retriveValueInPreferredUnit(atIndex i: Int) -> Int64 {
158+
return self.lock.withLock {
159+
let value = values[i].1
160+
guard let displayUnit = self.displayUnit else {
161+
return value
162+
}
163+
switch displayUnit {
164+
case .days: return (value / 1_000_000_000) * 60 * 60 * 24
165+
case .hours: return (value / 1_000_000_000) * 60 * 60
166+
case .minutes: return (value / 1_000_000_000) * 60
167+
case .seconds: return value / 1_000_000_000
168+
case .milliseconds: return value / 1_000_000
169+
case .nanoseconds: return value
170+
}
171+
}
172+
}
173+
149174
func recordNanoseconds(_ duration: Int64) {
150175
self.lock.withLock {
151176
values.append((Date(), duration))

0 commit comments

Comments
 (0)