packages feed

arbor-monad-metric-datadog 0.0.3 → 1.0.0

raw patch · 5 files changed

+68/−36 lines, 5 filesdep ~arbor-monad-metricdep ~containersnew-uploaderPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: arbor-monad-metric, containers

API changes (from Hackage documentation)

+ Arbor.Monad.Metric.Datadog.Internal: class ToStat a where {
+ Arbor.Monad.Metric.Datadog.Internal: instance Arbor.Monad.Metric.Datadog.Internal.ToStat Arbor.Monad.Metric.Type.Tag
+ Arbor.Monad.Metric.Datadog.Internal: toStat :: ToStat a => a -> StatType a
+ Arbor.Monad.Metric.Datadog.Internal: type family StatType a;
+ Arbor.Monad.Metric.Datadog.Internal: }
+ Arbor.Monad.Metric.Datadog.Internal.Show: showInt :: Int -> String

Files

arbor-monad-metric-datadog.cabal view
@@ -1,5 +1,5 @@ name:           arbor-monad-metric-datadog-version:        0.0.3+version:        1.0.0 description:    Please see the README on Github at <https://github.com/arbor/arbor-monad-metric-datadog#readme> synopsis:       Metric library backend for datadog. category:       Metrics@@ -23,6 +23,8 @@ library   exposed-modules:       Arbor.Monad.Metric.Datadog+      Arbor.Monad.Metric.Datadog.Internal+      Arbor.Monad.Metric.Datadog.Internal.Show   other-modules:       Paths_arbor_monad_metric_datadog   hs-source-dirs:@@ -32,7 +34,7 @@   build-depends:       base                          >= 4.7      && < 5     , arbor-datadog                 >= 0.0.0    && < 0.1-    , arbor-monad-metric            >= 0.0.2    && < 0.1+    , arbor-monad-metric            >= 1.1.0    && < 1.2     , bytestring                    >= 0.10.8   && < 0.11     , containers                    >= 0.5.10   && < 0.6     , generic-lens                  >= 1.0.0.2  && < 1.2@@ -49,10 +51,12 @@   type: exitcode-stdio-1.0   main-is: Spec.hs   other-modules:-      Arbor.Monad.Metric.Datadog       Arbor.Monad.Datadog.MetricApp       Arbor.Monad.Datadog.MetricSpec       Arbor.Monad.Datadog.UdpServer+      Arbor.Monad.Metric.Datadog+      Arbor.Monad.Metric.Datadog.Internal+      Arbor.Monad.Metric.Datadog.Internal.Show       Paths_arbor_monad_metric_datadog   hs-source-dirs:       test@@ -62,7 +66,7 @@   build-depends:       base                          >= 4.7      && < 5     , arbor-datadog                 >= 0.0.0    && < 0.1-    , arbor-monad-metric            >= 0.0.2    && < 0.1+    , arbor-monad-metric     , arbor-monad-metric-datadog     , bytestring                    >= 0.10.8   && < 0.11     , containers                    >= 0.5.10   && < 0.6
src/Arbor/Monad/Metric/Datadog.hs view
@@ -7,57 +7,54 @@   , mkEvent   ) where -import Arbor.Monad.Metric.Type   (Counter (..), Gauge (..), MonadMetrics, getMetricMapTVar)+import Arbor.Monad.Metric.Datadog.Internal+import Arbor.Monad.Metric.Datadog.Internal.Show+import Arbor.Monad.Metric.Type                  (Counter, Gauge, MonadMetrics, getMetricMapTVar) import Control.Lens import Control.Monad.IO.Class import Data.Foldable import Data.Generics.Product.Any import Data.Proxy-import Data.Semigroup            ((<>))+import Data.Semigroup                           ((<>))  import qualified Arbor.Monad.Metric        as C import qualified Arbor.Network.StatsD      as S import qualified Arbor.Network.StatsD.Type as Z import qualified Control.Concurrent.STM    as STM import qualified Data.Map.Strict           as M+import qualified Data.Set                  as S import qualified Data.Text                 as T  logStats :: (S.MonadStats m, MonadMetrics m) => m () logStats = do   tCounterMap <- getMetricMapTVar   (counters, _)  <- liftIO . STM.atomically $ STM.swapTVar tCounterMap M.empty >>= C.extractValues (Proxy @Counter)-  traverse_ S.sendMetric $ mkMetricsCounterTagged "counters" counters-  traverse_ S.sendMetric $ mkMetricsCounterNonTagged counters+  traverse_ S.sendMetric $ mkMetricsCounter counters    tGaugeMap <- getMetricMapTVar   (gauge, _)  <- liftIO . STM.atomically $ STM.swapTVar tGaugeMap M.empty >>= C.extractValues (Proxy @Gauge)-  traverse_ S.sendMetric $ mkMetricsGaugeTagged "gauge" gauge-  traverse_ S.sendMetric $ mkMetricsGaugeNonTagged gauge+  traverse_ S.sendMetric $ mkMetricsGauge gauge  metricName :: String -> T.Text metricName n = T.replace " " "_" (T.pack n) --- create metric m, but tag with stat:[actual stat name]-mkMetricsGaugeTagged :: String -> [(Gauge, Double)] -> [Z.Metric]-mkMetricsGaugeTagged m =-  fmap (\(Gauge n, i) -> S.gauge (Z.MetricName (metricName m)) id i & the @"tags" %~ ([S.tag "stat" (T.pack n)] ++))- -- create metrics for each counter-mkMetricsGaugeNonTagged :: [(Gauge, Double)] -> [S.Metric]-mkMetricsGaugeNonTagged =-  fmap (\(Gauge n, i) -> S.gauge (Z.MetricName (metricName n)) id i)---- create metric m, but tag with stat:[actual stat name]-mkMetricsCounterTagged :: String -> [(Counter, Int)] -> [Z.Metric]-mkMetricsCounterTagged m =-  fmap (\(Counter n, i) -> S.addCounter (Z.MetricName (metricName m)) id i & the @"tags" %~ ([S.tag "stat" (T.pack n)] ++))+mkMetricsGauge :: [(Gauge, Double)] -> [S.Metric]+mkMetricsGauge = fmap (uncurry mkGauge)+  where mkGauge :: Gauge -> Double -> S.Metric+        mkGauge g v = S.gauge (Z.MetricName (metricName (T.unpack name))) id v & the @"tags" .~ (toStat <$> tags)+          where name = g ^. the @"name"+                tags = g ^. the @"tags" & S.toList  -- create metrics for each counter-mkMetricsCounterNonTagged :: [(Counter, Int)] -> [S.Metric]-mkMetricsCounterNonTagged =-  fmap (\(Counter n, i) -> S.addCounter (Z.MetricName (metricName n)) id i)+mkMetricsCounter :: [(Counter, Int)] -> [S.Metric]+mkMetricsCounter = fmap (uncurry mkCounter)+  where mkCounter :: Counter -> Int -> S.Metric+        mkCounter g v = S.addCounter (Z.MetricName (metricName (T.unpack name))) id v & the @"tags" .~ (toStat <$> tags)+          where name = g ^. the @"name"+                tags = g ^. the @"tags" & S.toList  mkEvent :: [(String, Int)] -> String -> Z.Tag -> String -> Z.Event mkEvent stats etitle etag fn = S.event (T.pack etitle) desc & the @"tags" %~ ([etag] ++)   where desc = T.intercalate "\n" $ T.pack <$> ("File processed: " <> fn) : info-        info = (\(n, i) -> n <> ": " <> show i) <$> stats+        info = (\(n, i) -> n <> ": " <> showInt i) <$> stats
+ src/Arbor/Monad/Metric/Datadog/Internal.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TypeFamilies #-}++module Arbor.Monad.Metric.Datadog.Internal where++import qualified Arbor.Monad.Metric.Type as M+import qualified Arbor.Network.StatsD    as S++class ToStat a where+  type StatType a+  toStat :: a -> StatType a++instance ToStat M.Tag where+  type StatType M.Tag = S.Tag+  toStat (M.Tag n v) = S.tag n v
+ src/Arbor/Monad/Metric/Datadog/Internal/Show.hs view
@@ -0,0 +1,4 @@+module Arbor.Monad.Metric.Datadog.Internal.Show where++showInt :: Int -> String+showInt = show
test/Arbor/Monad/Datadog/MetricSpec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications    #-} @@ -6,16 +8,19 @@   ) where  import Control.Concurrent-import Control.Exception      (bracket)+import Control.Exception         (bracket)+import Control.Lens+import Control.Monad import Control.Monad.IO.Class+import Data.Function+import Data.Generics.Product.Any import Data.Proxy-import Data.Semigroup         ((<>))+import Data.Semigroup            ((<>))  import qualified Arbor.Monad.Datadog.MetricApp as A import qualified Arbor.Monad.Datadog.UdpServer as UDP import qualified Arbor.Monad.Metric            as M import qualified Arbor.Monad.Metric.Datadog    as M-import qualified Arbor.Monad.Metric.Type       as M import qualified Control.Concurrent.STM        as STM import qualified Data.ByteString.Char8         as BS import qualified Data.Map.Strict               as MAP@@ -36,6 +41,9 @@   STM.atomically $ STM.modifyTVar tMsgs (msg:)   putStrLn $ "From " ++ show addr ++ ": " ++ show msg +encodeMetrics :: [BS.ByteString] -> [BS.ByteString]+encodeMetrics = (:[]) . mconcat . fmap (<> "\n")+ spec :: Spec spec = describe "Arbor.Monad.MetricSpec" $ do   it "Metrics library actually sends statsd messages over UDP" $ requireTest $ do@@ -43,13 +51,18 @@     sock <- liftIO $ UDP.createUdpServer "5555"     threadId <- liftIO $ forkIO $ UDP.runUdpServer sock (handler tMessages)     liftIO $ threadDelay 1000000-    let counterExpected = "MetricApp.counters:10|c|#stat:test.counter\nMetricApp.test.counter:10|c\n" :: BS.ByteString-    let gaugeExpected = "MetricApp.gauge:20.000000|g|#stat:test.gauge\nMetricApp.test.gauge:20.000000|g\n" :: BS.ByteString+    -- let counterExpected = "MetricApp.counters:10|c|#stat:test.counter\nMetricApp.test.counter:10|c\n" :: BS.ByteString+    -- let gaugeExpected = "MetricApp.gauge:20.000000|g|#stat:test.gauge\nMetricApp.test.gauge:20.000000|g\n" :: BS.ByteString     liftIO $ A.runMetricApp $ do-      M.metric (M.Counter "test.counter") 10-      M.metric (M.Gauge   "test.gauge"  ) 20+      M.metric (M.counter "test.counter"                                        ) 10+      M.metric (M.gauge   "test.gauge"                                          ) 20+      M.metric (M.gauge   "test.gauge"  & the @"tags" .~ M.tags [("foo", "bar")]) 30       M.logStats     liftIO $ threadDelay 3000000     liftIO $ killThread threadId-    messages <- liftIO $ STM.readTVarIO tMessages-    messages === [counterExpected <> gaugeExpected]+    messages :: [BS.ByteString] <- liftIO $ STM.readTVarIO tMessages+    mconcat (BS.lines <$> messages) ===+      [ "MetricApp.test.counter:10|c"+      , "MetricApp.test.gauge:20.000000|g"+      , "MetricApp.test.gauge:30.000000|g|#foo:bar"+      ]