module Freckle.App.Scientist
  ( experimentPublishDatadog
  ) where

import Freckle.App.Prelude

import Freckle.App.Stats (HasStatsClient)
import qualified Freckle.App.Stats as Stats
import Scientist
import Scientist.Duration

-- | Publish experiment durations using "Freckle.App.Stats"
--
-- * Experiments are labeled "science.${name}"
-- * Results are tagged with "variant:${name}"
experimentPublishDatadog
  :: (MonadReader env m, MonadUnliftIO m, HasStatsClient env)
  => Result c a b
  -> m ()
experimentPublishDatadog :: forall env (m :: * -> *) c a b.
(MonadReader env m, MonadUnliftIO m, HasStatsClient env) =>
Result c a b -> m ()
experimentPublishDatadog Result c a b
result = Maybe (ResultDetails c a b)
-> (ResultDetails c a b -> m ()) -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (Result c a b -> Maybe (ResultDetails c a b)
forall c a b. Result c a b -> Maybe (ResultDetails c a b)
resultDetails Result c a b
result) ((ResultDetails c a b -> m ()) -> m ())
-> (ResultDetails c a b -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \ResultDetails c a b
details -> do
  let
    statName :: Text
statName = Text
"science." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ResultDetails c a b -> Text
forall c a b. ResultDetails c a b -> Text
resultDetailsExperimentName ResultDetails c a b
details
    ResultControl {a
Text
Duration
resultControlName :: Text
resultControlValue :: a
resultControlDuration :: Duration
resultControlName :: forall a. ResultControl a -> Text
resultControlValue :: forall a. ResultControl a -> a
resultControlDuration :: forall a. ResultControl a -> Duration
..} = ResultDetails c a b -> ResultControl a
forall c a b. ResultDetails c a b -> ResultControl a
resultDetailsControl ResultDetails c a b
details

  [(Text, Text)] -> m () -> m ()
forall env (m :: * -> *) a.
(MonadReader env m, HasStatsClient env) =>
[(Text, Text)] -> m a -> m a
Stats.tagged [(Text
"variant", Text
resultControlName)] (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
    Text -> Double -> m ()
forall (m :: * -> *) env.
(MonadUnliftIO m, MonadReader env m, HasStatsClient env) =>
Text -> Double -> m ()
Stats.gauge Text
statName (Double -> m ()) -> Double -> m ()
forall a b. (a -> b) -> a -> b
$
      Duration -> Double
durationToSeconds Duration
resultControlDuration

  NonEmpty (ResultCandidate b) -> (ResultCandidate b -> m ()) -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (ResultDetails c a b -> NonEmpty (ResultCandidate b)
forall c a b. ResultDetails c a b -> NonEmpty (ResultCandidate b)
resultDetailsCandidates ResultDetails c a b
details) ((ResultCandidate b -> m ()) -> m ())
-> (ResultCandidate b -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \ResultCandidate {Either SomeException b
Text
Duration
resultCandidateName :: Text
resultCandidateValue :: Either SomeException b
resultCandidateDuration :: Duration
resultCandidateName :: forall a. ResultCandidate a -> Text
resultCandidateValue :: forall a. ResultCandidate a -> Either SomeException a
resultCandidateDuration :: forall a. ResultCandidate a -> Duration
..} ->
    [(Text, Text)] -> m () -> m ()
forall env (m :: * -> *) a.
(MonadReader env m, HasStatsClient env) =>
[(Text, Text)] -> m a -> m a
Stats.tagged [(Text
"variant", Text
"candidate-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
resultCandidateName)] (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
      Text -> Double -> m ()
forall (m :: * -> *) env.
(MonadUnliftIO m, MonadReader env m, HasStatsClient env) =>
Text -> Double -> m ()
Stats.gauge Text
statName (Double -> m ()) -> Double -> m ()
forall a b. (a -> b) -> a -> b
$
        Duration -> Double
durationToSeconds Duration
resultCandidateDuration