packages feed

prometheus-0.1.0.0: src/System/Metrics/Prometheus/Encode.hs

{-# LANGUAGE OverloadedStrings #-}

module System.Metrics.Prometheus.Encode
       ( encodeMetrics
       , serializeMetrics
       ) where

import           Data.ByteString.Builder            (Builder, byteString, char8,
                                                     doubleDec, intDec,
                                                     toLazyByteString)
import           Data.ByteString.Lazy               (ByteString)
import           Data.List                          (intersperse)
import qualified Data.Map                           as Map
import           Data.Monoid                        ((<>))
import           Data.Text                          (Text, replace)
import           Data.Text.Encoding                 (encodeUtf8)

import           System.Metrics.Prometheus.MetricId (MetricId (..))
import           System.Metrics.Prometheus.Sample   (CounterSample (..),
                                                     GaugeSample (..),
                                                     MetricSample (..),
                                                     RegistrySample (..),
                                                     metricSample)


serializeMetrics :: RegistrySample -> ByteString
serializeMetrics = toLazyByteString . encodeMetrics


encodeMetrics :: RegistrySample -> Builder
encodeMetrics = mconcat . intersperse "\n\n" .
    map (uncurry encodeMetric) . Map.toList . unRegistrySample


encodeMetric :: MetricId -> MetricSample -> Builder
encodeMetric mid sample
    =  encodeHeader mid sample <> newline
    <> metricSample (encodeCounter mid) (encodeGauge mid) encodeHistogram encodeSummary sample


encodeHeader :: MetricId -> MetricSample -> Builder
encodeHeader mid sample
    =  "# HELP " <> encodeName mid <> space <> "help" <> newline
    <> "# TYPE " <> encodeName mid <> space <> encodeSampleType sample


-- escape :: Text -> Text
-- escape = replace "\\" "\\\" . replace "\"" ("\\" <> "\"")


encodeHistogram = undefined
encodeSummary = undefined


encodeCounter :: MetricId -> CounterSample -> Builder
encodeCounter mid counter = encodeMetricId mid <> space <> intDec (unCounterSample counter)


encodeGauge :: MetricId -> GaugeSample -> Builder
encodeGauge mid gauge = encodeMetricId mid <> space <> doubleDec (unGaugeSample gauge)


encodeSampleType :: MetricSample -> Builder
encodeSampleType = byteString . metricSample (const "counter")
    (const "gauge") (const "histogram") (const "summary")


encodeMetricId :: MetricId -> Builder
encodeMetricId mid = encodeName mid <> encodeLabels mid


encodeName :: MetricId -> Builder
encodeName = text . name


encodeLabels :: MetricId -> Builder
encodeLabels mid | Map.null (labels mid) = space
                 | otherwise =
                   openBracket
                   <> (mconcat . intersperse comma . map encodeLabel . Map.toList $ labels mid)
                   <> closeBracket


encodeLabel :: (Text, Text) -> Builder
encodeLabel (key, value) = text key <> equals <> text value


text :: Text -> Builder
text = byteString . encodeUtf8


space :: Builder
space = char8 ' '


newline :: Builder
newline = char8 '\n'


openBracket :: Builder
openBracket = char8 '{'


closeBracket :: Builder
closeBracket = char8 '}'


comma :: Builder
comma = char8 ','


equals :: Builder
equals = char8 '='