module System.Metrics.Prometheus.Encode.Text
       ( encodeMetrics
       ) where

import           Data.ByteString.Builder                         (Builder)
import           Data.Function                                   (on)
import           Data.List                                       (groupBy,
                                                                  intersperse)
import qualified Data.Map                                        as Map
import           Data.Monoid                                     ((<>))

import           System.Metrics.Prometheus.Encode.Text.Histogram (encodeHistogram)
import           System.Metrics.Prometheus.Encode.Text.MetricId  (encodeDouble,
                                                                  encodeHeader,
                                                                  encodeInt,
                                                                  encodeMetricId,
                                                                  newline,
                                                                  space)
import           System.Metrics.Prometheus.Metric                (MetricSample (..),
                                                                  metricSample)
import           System.Metrics.Prometheus.Metric.Counter        (CounterSample (..))
import           System.Metrics.Prometheus.Metric.Gauge          (GaugeSample (..))
import           System.Metrics.Prometheus.MetricId              (MetricId (..))
import           System.Metrics.Prometheus.Registry              (RegistrySample (..))


encodeMetrics :: RegistrySample -> Builder
encodeMetrics :: RegistrySample -> Builder
encodeMetrics = (Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
newline) (Builder -> Builder)
-> (RegistrySample -> Builder) -> RegistrySample -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder)
-> (RegistrySample -> [Builder]) -> RegistrySample -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
intersperse Builder
newline ([Builder] -> [Builder])
-> (RegistrySample -> [Builder]) -> RegistrySample -> [Builder]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([(MetricId, MetricSample)] -> Builder)
-> [[(MetricId, MetricSample)]] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map [(MetricId, MetricSample)] -> Builder
encodeMetricGroup
    ([[(MetricId, MetricSample)]] -> [Builder])
-> (RegistrySample -> [[(MetricId, MetricSample)]])
-> RegistrySample
-> [Builder]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(MetricId, MetricSample)] -> [[(MetricId, MetricSample)]]
forall b. [(MetricId, b)] -> [[(MetricId, b)]]
groupByName ([(MetricId, MetricSample)] -> [[(MetricId, MetricSample)]])
-> (RegistrySample -> [(MetricId, MetricSample)])
-> RegistrySample
-> [[(MetricId, MetricSample)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map MetricId MetricSample -> [(MetricId, MetricSample)]
forall k a. Map k a -> [(k, a)]
Map.toList (Map MetricId MetricSample -> [(MetricId, MetricSample)])
-> (RegistrySample -> Map MetricId MetricSample)
-> RegistrySample
-> [(MetricId, MetricSample)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RegistrySample -> Map MetricId MetricSample
unRegistrySample
  where groupByName :: [(MetricId, b)] -> [[(MetricId, b)]]
groupByName = ((MetricId, b) -> (MetricId, b) -> Bool)
-> [(MetricId, b)] -> [[(MetricId, b)]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
(==) (Name -> Name -> Bool)
-> ((MetricId, b) -> Name)
-> (MetricId, b)
-> (MetricId, b)
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (MetricId -> Name
name (MetricId -> Name)
-> ((MetricId, b) -> MetricId) -> (MetricId, b) -> Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MetricId, b) -> MetricId
forall a b. (a, b) -> a
fst))


encodeMetricGroup :: [(MetricId, MetricSample)] -> Builder
encodeMetricGroup :: [(MetricId, MetricSample)] -> Builder
encodeMetricGroup [(MetricId, MetricSample)]
group = MetricId -> MetricSample -> Builder
encodeHeader MetricId
mid MetricSample
sample Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
newline
    Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat (Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
intersperse Builder
newline ([Builder] -> [Builder]) -> [Builder] -> [Builder]
forall a b. (a -> b) -> a -> b
$ ((MetricId, MetricSample) -> Builder)
-> [(MetricId, MetricSample)] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (MetricId, MetricSample) -> Builder
encodeMetric [(MetricId, MetricSample)]
group)
  where
    (MetricId
mid, MetricSample
sample) = [(MetricId, MetricSample)] -> (MetricId, MetricSample)
forall a. [a] -> a
head [(MetricId, MetricSample)]
group


encodeMetric :: (MetricId, MetricSample) -> Builder
encodeMetric :: (MetricId, MetricSample) -> Builder
encodeMetric (MetricId
mid, MetricSample
sample) = (CounterSample -> Builder)
-> (GaugeSample -> Builder)
-> (HistogramSample -> Builder)
-> (SummarySample -> Builder)
-> MetricSample
-> Builder
forall a.
(CounterSample -> a)
-> (GaugeSample -> a)
-> (HistogramSample -> a)
-> (SummarySample -> a)
-> MetricSample
-> a
metricSample (MetricId -> CounterSample -> Builder
encodeCounter MetricId
mid) (MetricId -> GaugeSample -> Builder
encodeGauge MetricId
mid)
    (MetricId -> HistogramSample -> Builder
encodeHistogram MetricId
mid) (MetricId -> SummarySample -> Builder
forall a. a
encodeSummary MetricId
mid) MetricSample
sample
  where
    encodeSummary :: a
encodeSummary = a
forall a. HasCallStack => a
undefined


encodeCounter :: MetricId -> CounterSample -> Builder
encodeCounter :: MetricId -> CounterSample -> Builder
encodeCounter MetricId
mid CounterSample
counter = MetricId -> Builder
encodeMetricId MetricId
mid Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
space Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
encodeInt (CounterSample -> Int
unCounterSample CounterSample
counter)


encodeGauge :: MetricId -> GaugeSample -> Builder
encodeGauge :: MetricId -> GaugeSample -> Builder
encodeGauge MetricId
mid GaugeSample
gauge = MetricId -> Builder
encodeMetricId MetricId
mid Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
space Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Double -> Builder
forall f. RealFloat f => f -> Builder
encodeDouble (GaugeSample -> Double
unGaugeSample GaugeSample
gauge)