freckle-app 1.0.0.4 → 1.0.1.0
raw patch · 6 files changed
+187/−8 lines, 6 filesdep +ekg-coredep +unordered-containers
Dependencies added: ekg-core, unordered-containers
Files
- CHANGELOG.md +7/−2
- freckle-app.cabal +5/−1
- library/Freckle/App/Datadog.hs +20/−4
- library/Freckle/App/Datadog/Gauge.hs +90/−0
- library/Freckle/App/Datadog/Rts.hs +62/−0
- package.yaml +3/−1
CHANGELOG.md view
@@ -1,6 +1,11 @@-## [_Unreleased_](https://github.com/freckle/freckle-app/compare/v1.0.0.4...main)+## [_Unreleased_](https://github.com/freckle/freckle-app/compare/v1.0.1.0...main) -None.+- None.++## [v1.0.1.0](https://github.com/freckle/freckle-app/compare/v1.0.0.4...v1.0.1.0)++- Added `Freckle.App.Datadog.Gauge` for client side stateful gauges.+- Added `Freckle.App.Datadog.Rts` for sending RTS statistics to DataDog. ## [v1.0.0.4](https://github.com/freckle/freckle-app/compare/v1.0.0.3...v1.0.0.4)
freckle-app.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: freckle-app-version: 1.0.0.4+version: 1.0.1.0 license: MIT license-file: LICENSE maintainer: Freckle Education@@ -28,6 +28,8 @@ Freckle.App Freckle.App.Database Freckle.App.Datadog+ Freckle.App.Datadog.Gauge+ Freckle.App.Datadog.Rts Freckle.App.Env Freckle.App.Env.Internal Freckle.App.Ghci@@ -69,6 +71,7 @@ data-default >=0.7.1.1, datadog >=0.2.5.0, doctest >=0.17,+ ekg-core >=0.1.1.7, errors >=2.3.0, exceptions >=0.10.4, fast-logger >=3.0.5,@@ -104,6 +107,7 @@ transformers-base >=0.4.5.2, unliftio >=0.2.18, unliftio-core >=0.2.0.1,+ unordered-containers >=0.2.14.0, wai >=3.2.3, wai-extra >=3.1.6, yaml >=0.11.5.0,
library/Freckle/App/Datadog.hs view
@@ -16,7 +16,7 @@ -- * Higher-level operations , increment , counter- , guage+ , gauge , histogram , histogramSince , histogramSinceMs@@ -27,9 +27,11 @@ , envParseDogStatsSettings , envParseDogStatsTags , mkStatsClient- )-where + -- * To be removed in next major bump+ , guage+ ) where+ import Prelude import Control.Lens (set)@@ -78,6 +80,20 @@ -> m () counter name tags = sendAppMetricWithTags name tags Counter +gauge+ :: ( MonadUnliftIO m+ , MonadReader env m+ , HasDogStatsClient env+ , HasDogStatsTags env+ )+ => Text+ -> [(Text, Text)]+ -> Double+ -> m ()+gauge name tags = sendAppMetricWithTags name tags Gauge++{-# DEPRECATED guage "Use gauge instead" #-}+-- | Deprecated typo version of 'gauge' guage :: ( MonadUnliftIO m , MonadReader env m@@ -88,7 +104,7 @@ -> [(Text, Text)] -> Double -> m ()-guage name tags = sendAppMetricWithTags name tags Gauge+guage = gauge histogram :: ( MonadUnliftIO m
+ library/Freckle/App/Datadog/Gauge.hs view
@@ -0,0 +1,90 @@+-- | Stateful gauges for Datadog+module Freckle.App.Datadog.Gauge+ ( Gauge+ , new+ , increment+ , decrement+ , add+ , subtract+ ) where++import Prelude hiding (subtract)++import Control.Monad.IO.Unlift (MonadUnliftIO)+import Control.Monad.Reader+import Data.Int (Int64)+import Data.Text (Text)+import Freckle.App.Datadog (HasDogStatsClient, HasDogStatsTags, gauge)+import qualified System.Metrics.Gauge as EKG++-- | A data type containing all reporting values for a gauge+data Gauge = Gauge+ { name :: Text+ , tags :: [(Text, Text)]+ , ekgGauge :: EKG.Gauge+ }++-- | Create a gauge holding in memory state+new :: MonadIO m => Text -> [(Text, Text)] -> m Gauge+new name tags = Gauge name tags <$> liftIO EKG.new++-- | Increment gauge state and report its current value+increment+ :: ( MonadUnliftIO m+ , MonadReader env m+ , HasDogStatsClient env+ , HasDogStatsTags env+ )+ => Gauge+ -> m ()+increment = add 1++-- | Add to gauge state and report its current value+add+ :: ( MonadUnliftIO m+ , MonadReader env m+ , HasDogStatsClient env+ , HasDogStatsTags env+ )+ => Int64+ -> Gauge+ -> m ()+add i = withEKGGauge (`EKG.add` i)++-- | Decrement gauge state and report its current value+decrement+ :: ( MonadUnliftIO m+ , MonadReader env m+ , HasDogStatsClient env+ , HasDogStatsTags env+ )+ => Gauge+ -> m ()+decrement = subtract 1++-- | Subtract from gauge state and report its current value+subtract+ :: ( MonadUnliftIO m+ , MonadReader env m+ , HasDogStatsClient env+ , HasDogStatsTags env+ )+ => Int64+ -> Gauge+ -> m ()+subtract i = withEKGGauge (`EKG.subtract` i)++withEKGGauge+ :: ( MonadUnliftIO m+ , MonadReader env m+ , HasDogStatsClient env+ , HasDogStatsTags env+ )+ => (EKG.Gauge -> IO ())+ -> Gauge+ -> m ()+withEKGGauge f Gauge {..} = do+ current <- liftIO $ do+ f ekgGauge+ EKG.read ekgGauge+ gauge name tags $ fromIntegral current
+ library/Freckle/App/Datadog/Rts.hs view
@@ -0,0 +1,62 @@+-- | RTS statistics sent to Datadog+module Freckle.App.Datadog.Rts+ ( forkRtsStatPolling+ ) where++import Prelude++import qualified Control.Immortal as Immortal+import Control.Monad (void)+import Control.Monad.IO.Unlift (MonadUnliftIO, liftIO)+import Control.Monad.Reader (MonadReader)+import Data.Foldable (traverse_)+import qualified Data.HashMap.Strict as HashMap+import Data.Text (Text)+import Freckle.App.Datadog (HasDogStatsClient, HasDogStatsTags)+import qualified Freckle.App.Datadog as Datadog+import qualified System.Metrics as Ekg+import qualified System.Metrics.Distribution.Internal as Ekg+import UnliftIO.Concurrent (threadDelay)++-- | Initialize a thread to poll RTS stats+--+-- Stats are collected via `ekg-core` and 'System.Metrics.registerGcMetrics'+--+forkRtsStatPolling+ :: ( MonadUnliftIO m+ , MonadReader env m+ , HasDogStatsClient env+ , HasDogStatsTags env+ )+ => m ()+forkRtsStatPolling = do+ store <- liftIO Ekg.newStore+ liftIO $ Ekg.registerGcMetrics store++ void $ Immortal.create $ \_ -> do+ sample <- liftIO $ Ekg.sampleAll store+ traverse_ (uncurry flushEkgSample) $ HashMap.toList sample++ let seconds n = n * 1000000+ threadDelay $ seconds 1++flushEkgSample+ :: ( MonadUnliftIO m+ , MonadReader env m+ , HasDogStatsClient env+ , HasDogStatsTags env+ )+ => Text+ -> Ekg.Value+ -> m ()+flushEkgSample name = \case+ Ekg.Counter n -> Datadog.counter name [] $ fromIntegral n+ Ekg.Gauge n -> Datadog.gauge name [] $ fromIntegral n+ Ekg.Distribution d -> do+ Datadog.gauge (name <> "." <> "mean") [] $ Ekg.mean d+ Datadog.gauge (name <> "." <> "variance") [] $ Ekg.variance d+ Datadog.gauge (name <> "." <> "sum") [] $ Ekg.sum d+ Datadog.gauge (name <> "." <> "min") [] $ Ekg.min d+ Datadog.gauge (name <> "." <> "max") [] $ Ekg.max d+ Datadog.counter (name <> "." <> "count") [] $ fromIntegral $ Ekg.count d+ Ekg.Label _ -> pure ()
package.yaml view
@@ -1,6 +1,6 @@ --- name: freckle-app-version: 1.0.0.4+version: 1.0.1.0 maintainer: Freckle Education category: Utils github: freckle/freckle-app@@ -60,6 +60,7 @@ - data-default - datadog - doctest+ - ekg-core - errors - exceptions - fast-logger@@ -95,6 +96,7 @@ - transformers-base - unliftio - unliftio-core+ - unordered-containers - wai - wai-extra - yaml