module Composite.Ekg (EkgMetric(ekgMetric)) where
import Composite.Record ((:->)(Val), Rec((:&), RNil), Record)
import Data.Char (isUpper, toLower)
import Data.Functor.Identity (Identity(Identity))
import Data.Monoid ((<>))
import qualified Data.Text as Text
import Data.Proxy (Proxy(Proxy))
import Data.Text (Text, pack)
import GHC.TypeLits (KnownSymbol, symbolVal)
import System.Metrics (Store, createCounter, createGauge, createLabel, createDistribution)
import System.Metrics.Counter (Counter)
import System.Metrics.Gauge (Gauge)
import System.Metrics.Label (Label)
import System.Metrics.Distribution (Distribution)
class EkgMetric a where
ekgMetric :: Text -> Store -> IO a
instance forall a s rs. (EkgMetric a, EkgMetric (Record rs), KnownSymbol s) => EkgMetric (Record ((s :-> a) ': rs)) where
ekgMetric prefix store =
(:&)
<$> (Identity . Val <$> ekgMetric (prefix <> "." <> (upperScores . pack . symbolVal) (Proxy :: Proxy s)) store)
<*> ekgMetric prefix store
instance EkgMetric (Record '[]) where
ekgMetric _ _ = pure RNil
instance EkgMetric Counter where
ekgMetric = createCounter
instance EkgMetric Gauge where
ekgMetric = createGauge
instance EkgMetric Label where
ekgMetric = createLabel
instance EkgMetric Distribution where
ekgMetric = createDistribution
upperScores :: Text -> Text
upperScores = Text.dropWhile (== '_') . Text.concatMap score
where score :: Char -> Text
score c | isUpper c = "_" <> Text.singleton (toLower c)
score c = Text.singleton c