monad-metrics-extensible
tl;dr
This library simplifies using ekg in three ways:
- It allows specifying metrics as constructors of a user-defined GADT carrying both the metric name (to avoid typos) and the metric kind (a counter, a distribution and so on — to avoid code duplication). Multiple GADTs in the same appplication are supported (hence "extensible").
- It encapsulates managing all the necessary EKG objects on-demand via a monadic API.
- It allows defining new kinds of metrics in the user code (hence "extensible" one more time). You want a combined distribution + counter? No prob!
System.Metrics.Extensible
is your entry point of choice!
A quick example
First we enable a few extensions and import some packages:
{-# LANGUAGE DataKinds, GADTs, StandaloneDeriving #-}
import System.Metrics.Extensible
import System.Remote.Monitoring -- for ekg stuff
Then we define a type that represents the possible metrics in our application:
data SomeMetrics ty name where
SomeCounter :: SomeMetrics Counter "some_counter"
AnotherCounter :: SomeMetrics Counter "other_counter"
SomeGauge :: SomeMetrics Gauge "some_gauge"
The string literals are what will be shown via ekg UI.
There is a couple of requirements:
- The type shall be of the kind
* -> Symbol -> *
. - The first type argument (
Counter
andGauge
in the example above) shall be an instance ofTrackerLike
. All ekg counters are already instances of this class. - The type shall be comparable, hence we also do
deriving instance Eq (SomeMetrics ty name) deriving instance Ord (SomeMetrics ty name)
Then we can write our small program!
main :: IO ()
main = do
ekgServer <- forkServer "localhost" 8000
withMetricsStore ekgServer $ \store -> flip runMetricsT store $ do
track SomeCounter
track SomeGauge 42
-
withMetricsStore
creates the metrics store that's managed by this library and runs anIO
computation with that store. -
runMetricsT
is what runs the monad transformer giving access to the metrics. -
track
is the function that's responsible for updating the metrics. Its arguments depend on the specific metric that's being tracked: for instance, as can be seen in the example above,Counter
s have no arguments, whileGauge
s accept the corresponding new value.