content: module Prometheus.Metric.Observer (
      Observer(..)
  ,   observeDuration
  ,   timeAction
  ) where
  
  import Data.Ratio ((%))
  import Prometheus.MonadMonitor
  
  import Control.Monad.IO.Class
  import System.Clock (Clock(..), diffTimeSpec, getTime, toNanoSecs)
  
  -- | Interface shared by 'Summary' and 'Histogram'.
  class Observer metric where
      -- | Observe that a particular floating point value has occurred.
      -- For example, observe that this request took 0.23s.
      observe :: MonadMonitor m => metric -> Double -> m ()
  
  -- | Adds the duration in seconds of an IO action as an observation to an
  -- observer metric.
  --
  -- If the IO action throws an exception no duration will be observed.
  observeDuration :: (Observer metric, MonadIO m, MonadMonitor m) => metric -> m a -> m a
  observeDuration metric io = do
      (result, duration) <- timeAction io
      observe metric duration 
      return result
  
  
  -- | Evaluate @io@ and return its result as well as how long it took to evaluate,
  -- in seconds.
  timeAction :: MonadIO m => m a -> m (a, Double)
  timeAction io = do
      start  <- liftIO $ getTime Monotonic
      result <- io
      end    <- liftIO $ getTime Monotonic
      let duration = toNanoSecs (end `diffTimeSpec` start) % 1000000000
      return (result, fromRational duration)
  