packages feed

freckle-app-1.9.0.0: library/Network/Wai/Middleware/Stats.hs

module Network.Wai.Middleware.Stats
  ( addThreadContextFromStatsTags
  , requestStats
  ) where

import Freckle.App.Prelude

import Blammo.Logging (Pair, withThreadContext)
import Control.Lens ((^.))
import Control.Monad.Reader (runReaderT)
import Data.Aeson ((.=))
import qualified Freckle.App.Aeson as Key
import Freckle.App.Stats (HasStatsClient(..), tagsL)
import qualified Freckle.App.Stats as Stats
import Network.HTTP.Types.Status (Status(..))
import Network.Wai (Middleware, Request, requestMethod, responseStatus)

-- | Add any tags in the ambient 'StatsClient' to the logging context
addThreadContextFromStatsTags :: HasStatsClient env => env -> Middleware
addThreadContextFromStatsTags env app req respond = do
  let context = uncurry fromTag <$> env ^. statsClientL . tagsL
  withThreadContext context $ app req respond
 where
  fromTag :: Text -> Text -> Pair
  fromTag k v = Key.fromText k .= v

-- | Emit @requests@ and @response_time_ms@ metrics
requestStats
  :: HasStatsClient env => env -> (Request -> [(Text, Text)]) -> Middleware
requestStats env getTags app req respond = do
  start <- getCurrentTime
  app req $ \res -> do
    let
      tags =
        getTags req
          <> [ ("method", decodeUtf8 $ requestMethod req)
             , ("status", pack $ show $ statusCode $ responseStatus res)
             ]

    flip runReaderT env $ Stats.tagged tags $ do
      Stats.increment "requests"
      Stats.histogramSinceMs "response_time_ms" start

    respond res