prometheus 2.2.3 → 2.2.4
raw patch · 18 files changed
+536/−358 lines, 18 filesdep ~bytestringdep ~textdep ~transformers
Dependency ranges changed: bytestring, text, transformers
Files
- Example.hs +7/−6
- README.md +1/−1
- prometheus.cabal +3/−3
- src/System/Metrics/Prometheus/Concurrent/Registry.hs +42/−21
- src/System/Metrics/Prometheus/Concurrent/RegistryT.hs +30/−14
- src/System/Metrics/Prometheus/Encode/Text.hs +45/−29
- src/System/Metrics/Prometheus/Encode/Text/Histogram.hs +43/−26
- src/System/Metrics/Prometheus/Encode/Text/MetricId.hs +59/−39
- src/System/Metrics/Prometheus/Http/Push.hs +60/−44
- src/System/Metrics/Prometheus/Http/Scrape.hs +34/−27
- src/System/Metrics/Prometheus/Metric.hs +22/−14
- src/System/Metrics/Prometheus/Metric/Counter.hs +30/−16
- src/System/Metrics/Prometheus/Metric/Gauge.hs +18/−17
- src/System/Metrics/Prometheus/Metric/Histogram.hs +33/−29
- src/System/Metrics/Prometheus/Metric/Summary.hs +5/−5
- src/System/Metrics/Prometheus/MetricId.hs +21/−18
- src/System/Metrics/Prometheus/Registry.hs +51/−33
- src/System/Metrics/Prometheus/RegistryT.hs +32/−16
Example.hs view
@@ -2,19 +2,20 @@ module Example where -import Control.Monad.IO.Class (liftIO)-import System.Metrics.Prometheus.Http.Scrape (serveMetricsT)-import System.Metrics.Prometheus.Concurrent.RegistryT-import System.Metrics.Prometheus.Metric.Counter (inc)-import System.Metrics.Prometheus.MetricId+import Control.Monad.IO.Class (liftIO)+import System.Metrics.Prometheus.Concurrent.RegistryT+import System.Metrics.Prometheus.Http.Scrape (serveMetricsT)+import System.Metrics.Prometheus.Metric.Counter (inc)+import System.Metrics.Prometheus.MetricId + main :: IO () main = runRegistryT $ do -- Labels can be defined as lists or added to an empty label set connectSuccessGauge <- registerGauge "example_connections" (fromList [("login", "success")]) connectFailureGauge <- registerGauge "example_connections" (addLabel "login" "failure" mempty) connectCounter <- registerCounter "example_connection_total" mempty- latencyHistogram <- registerHistogram "example_round_trip_latency_ms" mempty [10, 20..100]+ latencyHistogram <- registerHistogram "example_round_trip_latency_ms" mempty [10, 20 .. 100] liftIO $ inc connectCounter -- increment a counter
README.md view
@@ -42,7 +42,7 @@ -- [...] pass metric handles to the rest of the app - serveMetricsT 8080 ["metrics"] -- http://localhost:8080/metric server+ serveMetricsT 8080 ["metrics"] -- http://localhost:8080/metrics server ``` ## Advanced Usage
prometheus.cabal view
@@ -1,5 +1,5 @@ name: prometheus-version: 2.2.3+version: 2.2.4 synopsis: Prometheus Haskell Client homepage: http://github.com/bitnomial/prometheus bug-reports: http://github.com/bitnomial/prometheus/issues@@ -90,8 +90,8 @@ , http-client-tls >= 0.3 && < 0.4 , http-types >= 0.8 && < 0.13 , network-uri >= 2.5 && < 2.7- , text >= 1.2 && < 1.3- , transformers >= 0.4 && < 0.6+ , text >= 1.2 && < 2.1+ , transformers >= 0.4 && < 0.7 , wai >= 3.2 && < 3.3 , warp >= 3.2 && < 3.5
src/System/Metrics/Prometheus/Concurrent/Registry.hs view
@@ -1,28 +1,39 @@-module System.Metrics.Prometheus.Concurrent.Registry- ( Registry- , new- , registerCounter- , registerGauge- , registerHistogram- , sample- ) where-+module System.Metrics.Prometheus.Concurrent.Registry (+ Registry,+ new,+ registerCounter,+ registerGauge,+ registerHistogram,+ listMetricIds,+ removeMetric,+ sample,+) where -import Control.Applicative ((<$>))-import Control.Concurrent.MVar (MVar,- modifyMVarMasked,- newMVar, withMVar)-import Data.Tuple (swap)+import Control.Applicative ((<$>))+import Control.Concurrent.MVar (+ MVar,+ modifyMVarMasked,+ newMVar,+ readMVar,+ withMVar,+ )+import Data.Tuple (swap) -import System.Metrics.Prometheus.Metric.Counter (Counter)-import System.Metrics.Prometheus.Metric.Gauge (Gauge)-import System.Metrics.Prometheus.Metric.Histogram (Histogram,- UpperBound)-import System.Metrics.Prometheus.MetricId (Labels, Name)-import qualified System.Metrics.Prometheus.Registry as R+import System.Metrics.Prometheus.Metric.Counter (Counter)+import System.Metrics.Prometheus.Metric.Gauge (Gauge)+import System.Metrics.Prometheus.Metric.Histogram (+ Histogram,+ UpperBound,+ )+import System.Metrics.Prometheus.MetricId (+ Labels,+ MetricId,+ Name,+ )+import qualified System.Metrics.Prometheus.Registry as R -newtype Registry = Registry { unRegistry :: MVar R.Registry }+newtype Registry = Registry {unRegistry :: MVar R.Registry} new :: IO Registry@@ -45,6 +56,16 @@ registerHistogram name labels buckets = flip modifyMVarMasked register . unRegistry where register = fmap swap . R.registerHistogram name labels buckets+++removeMetric :: MetricId -> Registry -> IO ()+removeMetric i = flip modifyMVarMasked remove . unRegistry+ where+ remove reg = pure (R.removeMetric i reg, ())+++listMetricIds :: Registry -> IO [MetricId]+listMetricIds = fmap R.listMetricIds . readMVar . unRegistry sample :: Registry -> IO R.RegistrySample
src/System/Metrics/Prometheus/Concurrent/RegistryT.hs view
@@ -2,24 +2,32 @@ module System.Metrics.Prometheus.Concurrent.RegistryT where -import Control.Applicative ((<$>))-import Control.Monad.IO.Class (MonadIO, liftIO)-import Control.Monad.Trans.Class (MonadTrans)-import Control.Monad.Trans.Reader (ReaderT (..),- ask)+import Control.Applicative ((<$>))+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.Trans.Class (MonadTrans)+import Control.Monad.Trans.Reader (+ ReaderT (..),+ ask,+ ) -import System.Metrics.Prometheus.Concurrent.Registry (Registry, new)+import System.Metrics.Prometheus.Concurrent.Registry (Registry, new) import qualified System.Metrics.Prometheus.Concurrent.Registry as R-import System.Metrics.Prometheus.Metric.Counter (Counter)-import System.Metrics.Prometheus.Metric.Gauge (Gauge)-import System.Metrics.Prometheus.Metric.Histogram (Histogram)-import qualified System.Metrics.Prometheus.Metric.Histogram as Histogram-import System.Metrics.Prometheus.MetricId (Labels, Name)-import System.Metrics.Prometheus.Registry (RegistrySample)+import System.Metrics.Prometheus.Metric.Counter (Counter)+import System.Metrics.Prometheus.Metric.Gauge (Gauge)+import System.Metrics.Prometheus.Metric.Histogram (Histogram)+import qualified System.Metrics.Prometheus.Metric.Histogram as Histogram+import System.Metrics.Prometheus.MetricId (+ Labels,+ MetricId,+ Name,+ )+import System.Metrics.Prometheus.Registry (+ RegistrySample,+ listMetricIds,+ ) -newtype RegistryT m a =- RegistryT { unRegistryT :: ReaderT Registry m a }+newtype RegistryT m a = RegistryT {unRegistryT :: ReaderT Registry m a} deriving (Monad, MonadTrans, Applicative, Functor, MonadIO) @@ -37,6 +45,14 @@ registerHistogram :: MonadIO m => Name -> Labels -> [Histogram.UpperBound] -> RegistryT m Histogram registerHistogram n l b = RegistryT ask >>= liftIO . R.registerHistogram n l b+++removeMetric :: MonadIO m => MetricId -> RegistryT m ()+removeMetric i = RegistryT ask >>= liftIO . R.removeMetric i+++listMetricIds :: MonadIO m => RegistryT m [MetricId]+listMetricIds = RegistryT ask >>= liftIO . R.listMetricIds sample :: Monad m => RegistryT m (IO RegistrySample)
src/System/Metrics/Prometheus/Encode/Text.hs view
@@ -1,45 +1,61 @@-module System.Metrics.Prometheus.Encode.Text- ( encodeMetrics- ) where+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 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 (..))+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 = (<> newline) . mconcat . intersperse newline . map encodeMetricGroup- . groupByName . Map.toList . unRegistrySample- where groupByName = groupBy ((==) `on` (name . fst))+encodeMetrics =+ (<> newline) . mconcat . intersperse newline . map encodeMetricGroup+ . groupByName+ . Map.toList+ . unRegistrySample+ where+ groupByName = groupBy ((==) `on` (name . fst)) encodeMetricGroup :: [(MetricId, MetricSample)] -> Builder-encodeMetricGroup group = encodeHeader mid sample <> newline- <> mconcat (intersperse newline $ map encodeMetric group)+encodeMetricGroup group =+ encodeHeader mid sample <> newline+ <> mconcat (intersperse newline $ map encodeMetric group) where (mid, sample) = head group encodeMetric :: (MetricId, MetricSample) -> Builder-encodeMetric (mid, sample) = metricSample (encodeCounter mid) (encodeGauge mid)- (encodeHistogram mid) (encodeSummary mid) sample+encodeMetric (mid, sample) =+ metricSample+ (encodeCounter mid)+ (encodeGauge mid)+ (encodeHistogram mid)+ (encodeSummary mid)+ sample where encodeSummary = undefined
src/System/Metrics/Prometheus/Encode/Text/Histogram.hs view
@@ -1,44 +1,61 @@ {-# LANGUAGE OverloadedStrings #-} -module System.Metrics.Prometheus.Encode.Text.Histogram- ( encodeHistogram- ) where-+module System.Metrics.Prometheus.Encode.Text.Histogram (+ encodeHistogram,+) where -import Data.ByteString.Builder (Builder)-import Data.List (intersperse)-import qualified Data.Map as Map-import Data.Monoid ((<>))+import Data.ByteString.Builder (Builder)+import Data.List (intersperse)+import qualified Data.Map as Map+import Data.Monoid ((<>)) -import System.Metrics.Prometheus.Encode.Text.MetricId (encodeDouble,- encodeInt,- encodeLabels,- encodeName,- newline, space,- textValue)-import System.Metrics.Prometheus.Metric.Histogram (HistogramSample (..),- UpperBound)-import System.Metrics.Prometheus.MetricId (MetricId (..),- addLabel)+import System.Metrics.Prometheus.Encode.Text.MetricId (+ encodeDouble,+ encodeInt,+ encodeLabels,+ encodeName,+ newline,+ space,+ textValue,+ )+import System.Metrics.Prometheus.Metric.Histogram (+ HistogramSample (..),+ UpperBound,+ )+import System.Metrics.Prometheus.MetricId (+ MetricId (..),+ addLabel,+ ) encodeHistogram :: MetricId -> HistogramSample -> Builder-encodeHistogram mid histogram- = encodeHistogramBuckets mid histogram <> newline- <> n <> "_sum" <> ls <> space <> encodeDouble (histSum histogram) <> newline- <> n <> "_count" <> ls <> space <> encodeInt (histCount histogram)+encodeHistogram mid histogram =+ encodeHistogramBuckets mid histogram <> newline+ <> n+ <> "_sum"+ <> ls+ <> space+ <> encodeDouble (histSum histogram)+ <> newline+ <> n+ <> "_count"+ <> ls+ <> space+ <> encodeInt (histCount histogram) where n = encodeName $ name mid ls = encodeLabels $ labels mid encodeHistogramBuckets :: MetricId -> HistogramSample -> Builder-encodeHistogramBuckets mid = mconcat . intersperse newline . map snd . Map.toList- . Map.mapWithKey (encodeHistogramBucket mid) . histBuckets+encodeHistogramBuckets mid =+ mconcat . intersperse newline . map snd . Map.toList+ . Map.mapWithKey (encodeHistogramBucket mid)+ . histBuckets encodeHistogramBucket :: MetricId -> UpperBound -> Double -> Builder-encodeHistogramBucket mid upperBound count- = encodeName (name mid) <> "_bucket" <> encodeLabels labels' <> space <> encodeDouble count+encodeHistogramBucket mid upperBound count =+ encodeName (name mid) <> "_bucket" <> encodeLabels labels' <> space <> encodeDouble count where labels' = addLabel "le" (textValue upperBound) (labels mid)
src/System/Metrics/Prometheus/Encode/Text/MetricId.hs view
@@ -1,46 +1,65 @@ {-# LANGUAGE OverloadedStrings #-} -module System.Metrics.Prometheus.Encode.Text.MetricId- ( encodeHeader- , encodeMetricId- , encodeLabels- , encodeName- , textValue- , encodeDouble- , encodeInt- , escape- , newline- , space- ) where+module System.Metrics.Prometheus.Encode.Text.MetricId (+ encodeHeader,+ encodeMetricId,+ encodeLabels,+ encodeName,+ textValue,+ encodeDouble,+ encodeInt,+ escape,+ newline,+ space,+) where -import Data.ByteString.Builder (Builder, byteString, char8,- intDec)-import Data.List (intersperse)-import Data.Monoid ((<>))-import Data.Text (Text, replace)-import Data.Text.Encoding (encodeUtf8)-import Data.Text.Lazy (toStrict)-import Data.Text.Lazy.Builder (toLazyText)-import Data.Text.Lazy.Builder.RealFloat (FPFormat (Generic),- formatRealFloat)-import Prelude hiding (null)+import Data.ByteString.Builder (+ Builder,+ byteString,+ char8,+ intDec,+ )+import Data.List (intersperse)+import Data.Monoid ((<>))+import Data.Text (Text, replace)+import Data.Text.Encoding (encodeUtf8)+import Data.Text.Lazy (toStrict)+import Data.Text.Lazy.Builder (toLazyText)+import Data.Text.Lazy.Builder.RealFloat (+ FPFormat (Generic),+ formatRealFloat,+ )+import Prelude hiding (null) -import System.Metrics.Prometheus.Metric (MetricSample (..),- metricSample)-import System.Metrics.Prometheus.MetricId (Labels (..), MetricId (..),- Name (..), null, toList)+import System.Metrics.Prometheus.Metric (+ MetricSample (..),+ metricSample,+ )+import System.Metrics.Prometheus.MetricId (+ Labels (..),+ MetricId (..),+ Name (..),+ null,+ toList,+ ) encodeHeader :: MetricId -> MetricSample -> Builder-encodeHeader mid sample- = "# TYPE " <> nm <> space <> encodeSampleType sample+encodeHeader mid sample =+ "# TYPE " <> nm <> space <> encodeSampleType sample+ where -- <> "# HELP " <> nm <> space <> escape "help" <> newline <>- where nm = encodeName (name mid)+ nm = encodeName (name mid) encodeSampleType :: MetricSample -> Builder-encodeSampleType = byteString . metricSample (const "counter")- (const "gauge") (const "histogram") (const "summary")+encodeSampleType =+ byteString+ . metricSample+ (const "counter")+ (const "gauge")+ (const "histogram")+ (const "summary") encodeMetricId :: MetricId -> Builder@@ -55,9 +74,9 @@ encodeLabels ls | null ls = space | otherwise =- openBracket- <> (mconcat . intersperse comma . map encodeLabel $ toList ls)- <> closeBracket+ openBracket+ <> (mconcat . intersperse comma . map encodeLabel $ toList ls)+ <> closeBracket encodeLabel :: (Text, Text) -> Builder@@ -65,10 +84,11 @@ textValue :: RealFloat f => f -> Text-textValue x | isInfinite x && x > 0 = "+Inf"- | isInfinite x && x < 0 = "-Inf"- | isNaN x = "NaN"- | otherwise = toStrict . toLazyText $ formatRealFloat Generic Nothing x+textValue x+ | isInfinite x && x > 0 = "+Inf"+ | isInfinite x && x < 0 = "-Inf"+ | isNaN x = "NaN"+ | otherwise = toStrict . toLazyText $ formatRealFloat Generic Nothing x encodeDouble :: RealFloat f => f -> Builder
src/System/Metrics/Prometheus/Http/Push.hs view
@@ -1,33 +1,38 @@ {-# LANGUAGE OverloadedStrings #-} -module System.Metrics.Prometheus.Http.Push- ( pushMetrics- , parseURI- )- where+module System.Metrics.Prometheus.Http.Push (+ pushMetrics,+ parseURI,+) where -import Control.Concurrent (threadDelay)-import Control.Monad (forever)-import Data.ByteString.Builder (toLazyByteString)-import Data.Map (foldMapWithKey)-import Data.Text (Text, unpack)-import Network.HTTP.Client (Request (..),- RequestBody (..),- getUri,- httpNoBody,- parseRequest,- requestBody,- requestFromURI,- requestHeaders)-import Network.HTTP.Types (hContentType, methodPut)-import Network.HTTP.Client.TLS (newTlsManager)-import Network.URI (URI (..), URIAuth,- nullURI)+import Control.Concurrent (threadDelay)+import Control.Monad (forever)+import Data.ByteString.Builder (toLazyByteString)+import Data.Map (foldMapWithKey)+import Data.Text (Text, unpack)+import Network.HTTP.Client (+ Request (..),+ RequestBody (..),+ getUri,+ httpNoBody,+ parseRequest,+ requestBody,+ requestFromURI,+ requestHeaders,+ )+import Network.HTTP.Client.TLS (newTlsManager)+import Network.HTTP.Types (hContentType, methodPut)+import Network.URI (+ URI (..),+ URIAuth,+ nullURI,+ ) -import System.Metrics.Prometheus.Encode.Text (encodeMetrics)-import System.Metrics.Prometheus.MetricId (Labels (..))-import System.Metrics.Prometheus.Registry (RegistrySample)+import System.Metrics.Prometheus.Encode.Text (encodeMetrics)+import System.Metrics.Prometheus.MetricId (Labels (..))+import System.Metrics.Prometheus.Registry (RegistrySample) + -- | Parses a uri such that -- @ -- parseURI "https://example.com"@@ -37,29 +42,40 @@ parseURI :: String -> Maybe URI parseURI = fmap getUri . parseRequest -pushMetrics :: URI -- ^ PushGateway URI name, including port number (ex: @parseUri https://myGateway.com:8080@)- -> Text -- ^ Job name- -> Labels -- ^ Label set to use as a grouping key for metrics- -> Int -- ^ Microsecond push frequency- -> IO RegistrySample -- ^ Action to get latest metrics- -> IO ()++pushMetrics ::+ -- | PushGateway URI name, including port number (ex: @parseUri https://myGateway.com:8080@)+ URI ->+ -- | Job name+ Text ->+ -- | Label set to use as a grouping key for metrics+ Labels ->+ -- | Microsecond push frequency+ Int ->+ -- | Action to get latest metrics+ IO RegistrySample ->+ IO () pushMetrics gatewayURI jobName labels frequencyMicros getSample = do- manager <- newTlsManager- gn <- maybe (error "Invalid URI Authority") pure gatewayName+ manager <- newTlsManager+ gn <- maybe (error "Invalid URI Authority") pure gatewayName requestUri <- requestFromURI $ buildUri scheme gn jobName labels forever $ getSample >>= flip httpNoBody manager . request requestUri >> threadDelay frequencyMicros where URI scheme gatewayName _ _ _ = gatewayURI- request req sample = req- { method = methodPut- , requestBody = RequestBodyLBS . toLazyByteString $ encodeMetrics sample- , requestHeaders = [(hContentType, "text/plain; version=0.0.4")]- }+ request req sample =+ req+ { method = methodPut+ , requestBody = RequestBodyLBS . toLazyByteString $ encodeMetrics sample+ , requestHeaders = [(hContentType, "text/plain; version=0.0.4")]+ } + buildUri :: String -> URIAuth -> Text -> Labels -> URI-buildUri scheme gatewayName jobName (Labels ls) = nullURI- { uriScheme = scheme- , uriAuthority = Just gatewayName- , uriPath = "/metrics/job/" ++ unpack jobName ++ foldMapWithKey labelPath ls- }- where labelPath k v = "/" ++ unpack k ++ "/" ++ unpack v+buildUri scheme gatewayName jobName (Labels ls) =+ nullURI+ { uriScheme = scheme+ , uriAuthority = Just gatewayName+ , uriPath = "/metrics/job/" ++ unpack jobName ++ foldMapWithKey labelPath ls+ }+ where+ labelPath k v = "/" ++ unpack k ++ "/" ++ unpack v
src/System/Metrics/Prometheus/Http/Scrape.hs view
@@ -1,34 +1,41 @@ {-# LANGUAGE OverloadedStrings #-} -module System.Metrics.Prometheus.Http.Scrape- ( Path- , serveMetrics- , serveMetricsT- , prometheusApp- )- where+module System.Metrics.Prometheus.Http.Scrape (+ Path,+ serveMetrics,+ serveMetricsT,+ prometheusApp,+) where -import Control.Applicative ((<$>))-import Control.Monad.IO.Class (MonadIO,- liftIO)-import Data.Text (Text)-import Network.HTTP.Types (hContentType,- methodGet,- status200,- status404)-import Network.Wai (Application,- Request,- Response,- pathInfo,- requestMethod,- responseBuilder,- responseLBS)-import Network.Wai.Handler.Warp (Port, run)+import Control.Applicative ((<$>))+import Control.Monad.IO.Class (+ MonadIO,+ liftIO,+ )+import Data.Text (Text)+import Network.HTTP.Types (+ hContentType,+ methodGet,+ status200,+ status404,+ )+import Network.Wai (+ Application,+ Request,+ Response,+ pathInfo,+ requestMethod,+ responseBuilder,+ responseLBS,+ )+import Network.Wai.Handler.Warp (Port, run) -import System.Metrics.Prometheus.Concurrent.RegistryT (RegistryT,- sample)-import System.Metrics.Prometheus.Encode.Text (encodeMetrics)-import System.Metrics.Prometheus.Registry (RegistrySample)+import System.Metrics.Prometheus.Concurrent.RegistryT (+ RegistryT,+ sample,+ )+import System.Metrics.Prometheus.Encode.Text (encodeMetrics)+import System.Metrics.Prometheus.Registry (RegistrySample) -- | The HTTP web route on which to serve data
src/System/Metrics/Prometheus/Metric.hs view
@@ -1,18 +1,22 @@ module System.Metrics.Prometheus.Metric where -import System.Metrics.Prometheus.Metric.Counter (Counter,- CounterSample)-import System.Metrics.Prometheus.Metric.Gauge (Gauge, GaugeSample)-import System.Metrics.Prometheus.Metric.Histogram (Histogram,- HistogramSample)-import System.Metrics.Prometheus.Metric.Summary (SummarySample)+import System.Metrics.Prometheus.Metric.Counter (+ Counter,+ CounterSample,+ )+import System.Metrics.Prometheus.Metric.Gauge (Gauge, GaugeSample)+import System.Metrics.Prometheus.Metric.Histogram (+ Histogram,+ HistogramSample,+ )+import System.Metrics.Prometheus.Metric.Summary (SummarySample) data Metric = CounterMetric Counter | GaugeMetric Gauge- -- | Summary S.Summary- | HistogramMetric Histogram+ | -- | Summary S.Summary+ HistogramMetric Histogram data MetricSample@@ -22,10 +26,14 @@ | SummaryMetricSample SummarySample -metricSample :: (CounterSample -> a) -> (GaugeSample -> a)- -> (HistogramSample -> a) -> (SummarySample -> a)- -> MetricSample -> a-metricSample f _ _ _ (CounterMetricSample s) = f s-metricSample _ f _ _ (GaugeMetricSample s) = f s+metricSample ::+ (CounterSample -> a) ->+ (GaugeSample -> a) ->+ (HistogramSample -> a) ->+ (SummarySample -> a) ->+ MetricSample ->+ a+metricSample f _ _ _ (CounterMetricSample s) = f s+metricSample _ f _ _ (GaugeMetricSample s) = f s metricSample _ _ f _ (HistogramMetricSample s) = f s-metricSample _ _ _ f (SummaryMetricSample s) = f s+metricSample _ _ _ f (SummaryMetricSample s) = f s
src/System/Metrics/Prometheus/Metric/Counter.hs view
@@ -1,20 +1,21 @@-module System.Metrics.Prometheus.Metric.Counter- ( Counter- , CounterSample (..)- , new- , add- , inc- , sample- , addAndSample- ) where-+module System.Metrics.Prometheus.Metric.Counter (+ Counter,+ CounterSample (..),+ new,+ add,+ inc,+ sample,+ addAndSample,+ set,+) where -import Control.Applicative ((<$>))-import Data.Atomics.Counter (AtomicCounter, incrCounter, newCounter)+import Control.Applicative ((<$>))+import Control.Monad (when)+import Data.Atomics.Counter (AtomicCounter, incrCounter, newCounter, writeCounter) -newtype Counter = Counter { unCounter :: AtomicCounter }-newtype CounterSample = CounterSample { unCounterSample :: Int }+newtype Counter = Counter {unCounter :: AtomicCounter}+newtype CounterSample = CounterSample {unCounterSample :: Int} new :: IO Counter@@ -22,8 +23,9 @@ addAndSample :: Int -> Counter -> IO CounterSample-addAndSample by | by >= 0 = fmap CounterSample . incrCounter by . unCounter- | otherwise = error "must be >= 0"+addAndSample by+ | by >= 0 = fmap CounterSample . incrCounter by . unCounter+ | otherwise = error "must be >= 0" add :: Int -> Counter -> IO ()@@ -36,3 +38,15 @@ sample :: Counter -> IO CounterSample sample = addAndSample 0+++-- | Write @i@ to the counter, if @i@ is more than the current value. This is+-- useful for when the count is maintained by a separate system (e.g. GHC's GC+-- counter).+--+-- WARNING: For multiple writers, the most recent one wins, which may not+-- preserve the increasing property. If you have stronger requirements than this,+-- please check with the maintainers. +-- See <https://github.com/bitnomial/prometheus/pull/44> for discussion.+set :: Int -> Counter -> IO ()+set i (Counter c) = writeCounter c i
src/System/Metrics/Prometheus/Metric/Gauge.hs view
@@ -1,22 +1,22 @@-module System.Metrics.Prometheus.Metric.Gauge- ( Gauge- , GaugeSample (..)- , new- , add- , sub- , inc- , dec- , set- , sample- , modifyAndSample- ) where+module System.Metrics.Prometheus.Metric.Gauge (+ Gauge,+ GaugeSample (..),+ new,+ add,+ sub,+ inc,+ dec,+ set,+ sample,+ modifyAndSample,+) where -import Control.Applicative ((<$>))-import Data.IORef (IORef, atomicModifyIORef', newIORef)+import Control.Applicative ((<$>))+import Data.IORef (IORef, atomicModifyIORef', newIORef) -newtype Gauge = Gauge { unGauge :: IORef Double }-newtype GaugeSample = GaugeSample { unGaugeSample :: Double }+newtype Gauge = Gauge {unGauge :: IORef Double}+newtype GaugeSample = GaugeSample {unGaugeSample :: Double} new :: IO Gauge@@ -25,7 +25,8 @@ modifyAndSample :: (Double -> Double) -> Gauge -> IO GaugeSample modifyAndSample f = flip atomicModifyIORef' g . unGauge- where g v = (f v, GaugeSample $ f v)+ where+ g v = (f v, GaugeSample $ f v) add :: Double -> Gauge -> IO ()
src/System/Metrics/Prometheus/Metric/Histogram.hs view
@@ -1,45 +1,47 @@ {-# LANGUAGE TupleSections #-} -module System.Metrics.Prometheus.Metric.Histogram- ( Histogram- , HistogramSample (..)- , Buckets- , UpperBound- , new- , observe- , sample- , observeAndSample- ) where-+module System.Metrics.Prometheus.Metric.Histogram (+ Histogram,+ HistogramSample (..),+ Buckets,+ UpperBound,+ new,+ observe,+ sample,+ observeAndSample,+) where -import Control.Applicative ((<$>))-import Control.Monad (void)-import Data.Bool (bool)-import Data.IORef (IORef, atomicModifyIORef', newIORef,- readIORef)-import Data.Map.Strict (Map)-import qualified Data.Map.Strict as Map+import Control.Applicative ((<$>))+import Control.Monad (void)+import Data.Bool (bool)+import Data.IORef (+ IORef,+ atomicModifyIORef',+ newIORef,+ readIORef,+ )+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map -newtype Histogram = Histogram { unHistogram :: IORef HistogramSample }+newtype Histogram = Histogram {unHistogram :: IORef HistogramSample} type UpperBound = Double -- Inclusive upper bounds type Buckets = Map UpperBound Double -data HistogramSample =- HistogramSample+data HistogramSample = HistogramSample { histBuckets :: !Buckets- , histSum :: !Double- , histCount :: !Int+ , histSum :: !Double+ , histCount :: !Int } new :: [UpperBound] -> IO Histogram new buckets = Histogram <$> newIORef empty where- empty = HistogramSample (Map.fromList $ map (, 0) (read "Infinity" : buckets)) zeroSum zeroCount+ empty = HistogramSample (Map.fromList $ map (,0) (read "Infinity" : buckets)) zeroSum zeroCount zeroSum = 0.0 zeroCount = 0 @@ -49,10 +51,11 @@ where update histData = (hist' histData, histData) hist' histData =- histData { histBuckets = updateBuckets x $ histBuckets histData- , histSum = histSum histData + x- , histCount = histCount histData + 1- }+ histData+ { histBuckets = updateBuckets x $ histBuckets histData+ , histSum = histSum histData + x+ , histCount = histCount histData + 1+ } observe :: Double -> Histogram -> IO ()@@ -61,7 +64,8 @@ updateBuckets :: Double -> Buckets -> Buckets updateBuckets x = Map.mapWithKey updateBucket- where updateBucket key val = bool val (val + 1) (x <= key)+ where+ updateBucket key val = bool val (val + 1) (x <= key) sample :: Histogram -> IO HistogramSample
src/System/Metrics/Prometheus/Metric/Summary.hs view
@@ -1,10 +1,10 @@ module System.Metrics.Prometheus.Metric.Summary where -import Data.Map.Strict (Map)+import Data.Map.Strict (Map) -data SummarySample =- SummarySample++data SummarySample = SummarySample { sumQuantiles :: !(Map Double Int)- , sumSum :: !Int- , sumCount :: !Int+ , sumSum :: !Int+ , sumCount :: !Int }
src/System/Metrics/Prometheus/MetricId.hs view
@@ -1,33 +1,36 @@-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-} module System.Metrics.Prometheus.MetricId where -import Data.Char (isDigit)-import Data.Bifunctor (first)-import Data.Map (Map)-import qualified Data.Map as Map-import Data.Monoid (Monoid)-import Data.Semigroup (Semigroup)-import Data.String (IsString(..))-import Data.Text (Text)+import Data.Bifunctor (first)+import Data.Char (isDigit)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Monoid (Monoid)+import Data.Semigroup (Semigroup)+import Data.String (IsString (..))+import Data.Text (Text) import qualified Data.Text as Text-import Prelude hiding (null)+import Prelude hiding (null) + -- | Construct with 'makeName' to ensure that names use only valid characters-newtype Name = Name { unName :: Text } deriving (Show, Eq, Ord, Monoid, Semigroup)+newtype Name = Name {unName :: Text} deriving (Show, Eq, Ord, Monoid, Semigroup) + instance IsString Name where- fromString = makeName . Text.pack+ fromString = makeName . Text.pack -newtype Labels = Labels { unLabels :: Map Text Text } deriving (Show, Eq, Ord, Monoid, Semigroup) +newtype Labels = Labels {unLabels :: Map Text Text} deriving (Show, Eq, Ord, Monoid, Semigroup) -data MetricId =- MetricId- { name :: Name++data MetricId = MetricId+ { name :: Name , labels :: Labels- } deriving (Eq, Ord, Show)+ }+ deriving (Eq, Ord, Show) addLabel :: Text -> Text -> Labels -> Labels@@ -53,7 +56,7 @@ -- first character is only valid as a later character. makeValid :: Text -> Text makeValid "" = "_"-makeValid txt = prefix_ <> Text.map (\c -> if allowedChar c then c else '_' ) txt+makeValid txt = prefix_ <> Text.map (\c -> if allowedChar c then c else '_') txt where prefix_ = if isDigit (Text.head txt) then "_" else "" allowedChar :: Char -> Bool
src/System/Metrics/Prometheus/Registry.hs view
@@ -1,37 +1,47 @@ {-# LANGUAGE DeriveDataTypeable #-} -module System.Metrics.Prometheus.Registry- ( Registry- , RegistrySample (..)- , new- , registerCounter- , registerGauge- , registerHistogram- , sample- ) where+module System.Metrics.Prometheus.Registry (+ Registry,+ RegistrySample (..),+ new,+ registerCounter,+ registerGauge,+ registerHistogram,+ listMetricIds,+ removeMetric,+ sample,+) where -import Control.Applicative ((<$>))-import Control.Exception (Exception, throw)-import Data.Map (Map)-import qualified Data.Map as Map-import Data.Typeable (Typeable)+import Control.Applicative ((<$>))+import Control.Exception (Exception, throw)+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Typeable (Typeable) -import System.Metrics.Prometheus.Metric (Metric (..),- MetricSample (..))-import System.Metrics.Prometheus.Metric.Counter (Counter)-import qualified System.Metrics.Prometheus.Metric.Counter as Counter-import System.Metrics.Prometheus.Metric.Gauge (Gauge)-import qualified System.Metrics.Prometheus.Metric.Gauge as Gauge-import System.Metrics.Prometheus.Metric.Histogram (Histogram,- UpperBound)+import System.Metrics.Prometheus.Metric (+ Metric (..),+ MetricSample (..),+ )+import System.Metrics.Prometheus.Metric.Counter (Counter)+import qualified System.Metrics.Prometheus.Metric.Counter as Counter+import System.Metrics.Prometheus.Metric.Gauge (Gauge)+import qualified System.Metrics.Prometheus.Metric.Gauge as Gauge+import System.Metrics.Prometheus.Metric.Histogram (+ Histogram,+ UpperBound,+ ) import qualified System.Metrics.Prometheus.Metric.Histogram as Histogram-import System.Metrics.Prometheus.MetricId (Labels (..),- MetricId (MetricId),- Name (..))+import System.Metrics.Prometheus.MetricId (+ Labels (..),+ MetricId (MetricId),+ Name (..),+ ) -newtype Registry = Registry { unRegistry :: Map MetricId Metric }-newtype RegistrySample = RegistrySample { unRegistrySample :: Map MetricId MetricSample } +newtype Registry = Registry {unRegistry :: Map MetricId Metric}+newtype RegistrySample = RegistrySample {unRegistrySample :: Map MetricId MetricSample}++ newtype KeyError = KeyError MetricId deriving (Show, Typeable) instance Exception KeyError @@ -45,8 +55,8 @@ counter <- Counter.new return (counter, Registry $ Map.insertWithKey collision mid (CounterMetric counter) (unRegistry registry)) where- mid = MetricId name labels- collision k _ _ = throw (KeyError k)+ mid = MetricId name labels+ collision k _ _ = throw (KeyError k) registerGauge :: Name -> Labels -> Registry -> IO (Gauge, Registry)@@ -54,8 +64,8 @@ gauge <- Gauge.new return (gauge, Registry $ Map.insertWithKey collision mid (GaugeMetric gauge) (unRegistry registry)) where- mid = MetricId name labels- collision k _ _ = throw (KeyError k)+ mid = MetricId name labels+ collision k _ _ = throw (KeyError k) registerHistogram :: Name -> Labels -> [UpperBound] -> Registry -> IO (Histogram, Registry)@@ -63,8 +73,16 @@ histogram <- Histogram.new buckets return (histogram, Registry $ Map.insertWithKey collision mid (HistogramMetric histogram) (unRegistry registry)) where- mid = MetricId name labels- collision k _ _ = throw (KeyError k)+ mid = MetricId name labels+ collision k _ _ = throw (KeyError k)+++removeMetric :: MetricId -> Registry -> Registry+removeMetric i (Registry m) = Registry . Map.delete i $ m+++listMetricIds :: Registry -> [MetricId]+listMetricIds = Map.keys . unRegistry sample :: Registry -> IO RegistrySample
src/System/Metrics/Prometheus/RegistryT.hs view
@@ -2,26 +2,34 @@ module System.Metrics.Prometheus.RegistryT where -import Control.Applicative ((<$>))-import Control.Monad.IO.Class (MonadIO, liftIO)-import Control.Monad.Trans.Class (MonadTrans)-import Control.Monad.Trans.State.Strict (StateT (..),- evalStateT,- execStateT, get)+import Control.Applicative ((<$>))+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.Trans.Class (MonadTrans)+import Control.Monad.Trans.State.Strict (+ StateT (..),+ evalStateT,+ execStateT,+ get,+ ) -import System.Metrics.Prometheus.Metric.Counter (Counter)-import System.Metrics.Prometheus.Metric.Gauge (Gauge)-import System.Metrics.Prometheus.Metric.Histogram (Histogram)+import System.Metrics.Prometheus.Metric.Counter (Counter)+import System.Metrics.Prometheus.Metric.Gauge (Gauge)+import System.Metrics.Prometheus.Metric.Histogram (Histogram) import qualified System.Metrics.Prometheus.Metric.Histogram as Histogram-import System.Metrics.Prometheus.MetricId (Labels, Name)-import System.Metrics.Prometheus.Registry (Registry,- RegistrySample,- new)-import qualified System.Metrics.Prometheus.Registry as R+import System.Metrics.Prometheus.MetricId (+ Labels,+ MetricId,+ Name,+ )+import System.Metrics.Prometheus.Registry (+ Registry,+ RegistrySample,+ new,+ )+import qualified System.Metrics.Prometheus.Registry as R -newtype RegistryT m a =- RegistryT { unRegistryT :: StateT Registry m a }+newtype RegistryT m a = RegistryT {unRegistryT :: StateT Registry m a} deriving (Monad, MonadTrans, Applicative, Functor, MonadIO) @@ -51,6 +59,14 @@ registerHistogram :: MonadIO m => Name -> Labels -> [Histogram.UpperBound] -> RegistryT m Histogram registerHistogram n l u = withRegistry (liftIO . R.registerHistogram n l u)+++removeMetric :: MonadIO m => MetricId -> RegistryT m ()+removeMetric i = withRegistry (pure . (,) () . R.removeMetric i)+++listMetricIds :: MonadIO m => RegistryT m [MetricId]+listMetricIds = R.listMetricIds <$> RegistryT get sample :: Monad m => RegistryT m (IO RegistrySample)