module Freckle.App.Scientist
  ( experimentPublishDatadog
  ) where

import Freckle.App.Prelude

import Data.List.NonEmpty as NE
import qualified Freckle.App.Datadog as Datadog
import Scientist
import Scientist.Duration

-- | Publish experiment durations to Datadog
--
-- * Experiments are labeled "science.${name}"
-- * Control results are tagged with "variant:control"
-- * Candidates are tagged with "variant:control-${i}"
--
experimentPublishDatadog
  :: ( MonadReader env m
     , MonadUnliftIO m
     , Datadog.HasDogStatsClient env
     , Datadog.HasDogStatsTags env
     )
  => Result c a b
  -> m ()
experimentPublishDatadog :: 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
  Text -> [(Text, Text)] -> Double -> m ()
forall (m :: * -> *) env.
(MonadUnliftIO m, MonadReader env m, HasDogStatsClient env,
 HasDogStatsTags env) =>
Text -> [(Text, Text)] -> Double -> m ()
Datadog.gauge Text
statName [(Text
"variant", Text
"control")]
    (Double -> m ()) -> Double -> m ()
forall a b. (a -> b) -> a -> b
$ Duration -> Double
durationToSeconds
    (Duration -> Double) -> Duration -> Double
forall a b. (a -> b) -> a -> b
$ ResultControl a -> Duration
forall a. ResultControl a -> Duration
resultControlDuration
    (ResultControl a -> Duration) -> ResultControl a -> Duration
forall a b. (a -> b) -> a -> b
$ ResultDetails c a b -> ResultControl a
forall c a b. ResultDetails c a b -> ResultControl a
resultDetailsControl ResultDetails c a b
details
  NonEmpty (ResultCandidate b, Int)
-> ((ResultCandidate b, Int) -> m ()) -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (NonEmpty (ResultCandidate b)
-> NonEmpty Int -> NonEmpty (ResultCandidate b, Int)
forall a b. NonEmpty a -> NonEmpty b -> NonEmpty (a, b)
NE.zip (ResultDetails c a b -> NonEmpty (ResultCandidate b)
forall c a b. ResultDetails c a b -> NonEmpty (ResultCandidate b)
resultDetailsCandidates ResultDetails c a b
details) ([Int] -> NonEmpty Int
forall a. [a] -> NonEmpty a
NE.fromList [Int
1 ..]))
    (((ResultCandidate b, Int) -> m ()) -> m ())
-> ((ResultCandidate b, Int) -> m ()) -> m ()
forall a b. (a -> b) -> a -> b
$ \(ResultCandidate b
candidate, Int
i :: Int) -> do
        Text -> [(Text, Text)] -> Double -> m ()
forall (m :: * -> *) env.
(MonadUnliftIO m, MonadReader env m, HasDogStatsClient env,
 HasDogStatsTags env) =>
Text -> [(Text, Text)] -> Double -> m ()
Datadog.gauge Text
statName [(Text
"variant", Text
"candidate-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow Int
i)]
          (Double -> m ()) -> Double -> m ()
forall a b. (a -> b) -> a -> b
$ Duration -> Double
durationToSeconds
          (Duration -> Double) -> Duration -> Double
forall a b. (a -> b) -> a -> b
$ ResultCandidate b -> Duration
forall a. ResultCandidate a -> Duration
resultCandidateDuration ResultCandidate b
candidate