wSimilar to what we are defining for logging, we would like to suggest an abstract metrics API which will allow application owners to plug-in different metrics backends, and library developers to emit metrics without getting in the way. Reasoning for such architecture is summarized in here, that post is about logging but the same is true for metrics as well.
An example for such abstract API could look something like:
public protocol Counter: AnyObject {
func increment<DataType: BinaryInteger>(_ value: DataType)
}
public protocol Recorder: AnyObject {
func record<DataType: BinaryInteger>(_ value: DataType)
func record<DataType: BinaryFloatingPoint>(_ value: DataType)
}
public protocol Timer: AnyObject {
func recordNanoseconds(_ duration: Int64)
}
public protocol MetricsHandler {
func makeCounter(label: String, dimensions: [(String, String)]) -> Counter
func makeRecorder(label: String, dimensions: [(String, String)], aggregate: Bool) -> Recorder
func makeTimer(label: String, dimensions: [(String, String)]) -> Timer
}
public extension MetricsHandler {
@inlinable
func makeGauge(label: String, dimensions: [(String, String)] = []) -> Recorder {
return self.makeRecorder(label: label, dimensions: dimensions, aggregate: false)
}
}
this means:
-
the actual metrics library (eg https://forums.swift.org/t/client-side-prometheus-implementation) will implement
MetricsHandler
-
the application owner bootstrap the with metrics library of choice (exact API tbd)
-
application and libraries developers call something like the below when they want to emit metrics
let counter = Metrics.makeCounter("foo")
...
counter.increment()`