monad-metrics-extensible: An extensible and type-safe wrapper around EKG metrics

[ bsd3, library, web ] [ Propose Tags ]
Versions [RSS],,
Change log
Dependencies base (>=4.7 && <5), dependent-map, dependent-sum, ekg, ekg-core, exceptions, mtl, stm, text, time [details]
License BSD-3-Clause
Copyright 2019 Georg Rudoy
Author Georg Rudoy
Category Web
Home page
Bug tracker
Source repo head: git clone
Uploaded by 0xd34df00d at 2021-02-01T23:05:09Z
Distributions NixOS:
Downloads 949 total (5 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2021-02-01 [all 1 reports]

Readme for monad-metrics-extensible-

[back to package description]


Build Status Hackage Stackage LTS Stackage Nightly


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 and Gauge in the example above) shall be an instance of TrackerLike. 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 an IO 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, Counters have no arguments, while Gauges accept the corresponding new value.