{-# language OverloadedStrings #-}
module Prometheus.Export.Text (
exportMetricsAsText
) where
import Prometheus.Info
import Prometheus.Metric
import Prometheus.Registry
import Control.Monad.IO.Class
import qualified Data.ByteString.Builder as Build
import qualified Data.ByteString.Lazy as BS
import Data.Foldable (foldMap)
import Data.Monoid ((<>), mempty, mconcat)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
exportMetricsAsText :: MonadIO m => m BS.ByteString
exportMetricsAsText :: forall (m :: * -> *). MonadIO m => m ByteString
exportMetricsAsText = do
[SampleGroup]
samples <- forall (m :: * -> *). MonadIO m => m [SampleGroup]
collectMetrics
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Builder -> ByteString
Build.toLazyByteString forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap SampleGroup -> Builder
exportSampleGroup [SampleGroup]
samples
exportSampleGroup :: SampleGroup -> Build.Builder
exportSampleGroup :: SampleGroup -> Builder
exportSampleGroup (SampleGroup Info
info SampleType
ty [Sample]
samples) =
if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Sample]
samples
then forall a. Monoid a => a
mempty
else Builder
prefix forall a. Semigroup a => a -> a -> a
<> Builder
exportedSamples
where
exportedSamples :: Builder
exportedSamples = [Sample] -> Builder
exportSamples [Sample]
samples
name :: Text
name = Info -> Text
metricName Info
info
help :: Text
help = Info -> Text
metricHelp Info
info
prefix :: Builder
prefix = ByteString -> Builder
Build.byteString forall a b. (a -> b) -> a -> b
$ Text -> ByteString
T.encodeUtf8 forall a b. (a -> b) -> a -> b
$ [Text] -> Text
T.unlines [
Text
"# HELP " forall a. Semigroup a => a -> a -> a
<> Text
name forall a. Semigroup a => a -> a -> a
<> Text
" " forall a. Semigroup a => a -> a -> a
<> (Char -> Text) -> Text -> Text
T.concatMap Char -> Text
escape Text
help
, Text
"# TYPE " forall a. Semigroup a => a -> a -> a
<> Text
name forall a. Semigroup a => a -> a -> a
<> Text
" " forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (forall a. Show a => a -> String
show SampleType
ty)
]
escape :: Char -> Text
escape Char
'\n' = Text
"\\n"
escape Char
'\\' = Text
"\\\\"
escape Char
other = String -> Text
T.pack [Char
other]
exportSamples :: [Sample] -> Build.Builder
exportSamples :: [Sample] -> Builder
exportSamples [Sample]
samples =
forall a. Monoid a => [a] -> a
mconcat [ Sample -> Builder
exportSample Sample
s forall a. Semigroup a => a -> a -> a
<> Char -> Builder
Build.charUtf8 Char
'\n' | Sample
s <- [Sample]
samples ]
exportSample :: Sample -> Build.Builder
exportSample :: Sample -> Builder
exportSample (Sample Text
name LabelPairs
labels ByteString
value) =
ByteString -> Builder
Build.byteString (Text -> ByteString
T.encodeUtf8 Text
name)
forall a. Semigroup a => a -> a -> a
<> (case LabelPairs
labels of
[] -> forall a. Monoid a => a
mempty
(Text, Text)
l:LabelPairs
ls ->
Char -> Builder
Build.charUtf8 Char
'{'
forall a. Semigroup a => a -> a -> a
<> (Text, Text) -> Builder
exportLabel (Text, Text)
l
forall a. Semigroup a => a -> a -> a
<> forall a. Monoid a => [a] -> a
mconcat [ Char -> Builder
Build.charUtf8 Char
',' forall a. Semigroup a => a -> a -> a
<> (Text, Text) -> Builder
exportLabel (Text, Text)
l' | (Text, Text)
l' <- LabelPairs
ls ]
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
Build.charUtf8 Char
'}')
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
Build.charUtf8 Char
' '
forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
Build.byteString ByteString
value
exportLabel :: (Text, Text) -> Build.Builder
exportLabel :: (Text, Text) -> Builder
exportLabel (Text
key, Text
value) =
ByteString -> Builder
Build.byteString (Text -> ByteString
T.encodeUtf8 Text
key)
forall a. Semigroup a => a -> a -> a
<> Char -> Builder
Build.charUtf8 Char
'='
forall a. Semigroup a => a -> a -> a
<> String -> Builder
Build.stringUtf8 (forall a. Show a => a -> String
show Text
value)