packages feed

katip-wai-0.1.2.0: test/LogEntry.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}

module LogEntry (
  Headers (..),
  Request (..),
  Response (..),
  LogData (..),
  LogEntry (..),
  toLogEntry,
  isMostlySameAs,
) where

import Data.Aeson ((.:))
import qualified Data.Aeson as Aeson
import Data.Function (on)
import Data.Text (Text)
import Data.UUID (UUID)
import GHC.Generics (Generic)
import GHC.Natural (Natural)
import qualified Katip

data Headers = Headers
  { host :: Maybe Text
  , referer :: Maybe Text
  , userAgent :: Maybe Text
  , range :: Maybe Text
  }
  deriving (Show, Generic, Eq)

instance Aeson.FromJSON Headers

data Request = Request
  { id :: UUID
  , httpVersion :: Text
  , remoteHost :: Text
  , isSecure :: Bool
  , method :: Text
  , path :: Text
  , queryString :: [(Text, Maybe Text)]
  , bodyLength :: Text
  , headers :: Headers
  }
  deriving (Show, Generic)

instance Aeson.FromJSON Request

data Response = Response
  { elapsedTimeInNanoSeconds :: Natural
  , status :: Int
  }
  deriving (Show, Generic)

instance Aeson.FromJSON Response

data LogData = LogData
  { request :: Maybe Request
  , response :: Maybe Response
  }
  deriving (Generic, Show)

instance Aeson.FromJSON LogData

data LogEntry = LogEntry
  { logMessage :: Text
  , logData :: LogData
  , logSeverity :: Katip.Severity
  }
  deriving (Show)

instance Aeson.FromJSON LogEntry where
  parseJSON = Aeson.withObject "LogEntry" $ \obj ->
    LogEntry <$> (obj .: "msg") <*> (obj .: "data") <*> (obj .: "sev")

toLogEntry :: Aeson.Value -> IO LogEntry
toLogEntry value =
  case Aeson.fromJSON value of
    Aeson.Success entry -> pure entry
    Aeson.Error reason -> fail reason

isMostlySameAs :: LogEntry -> LogEntry -> Bool
isMostlySameAs log1 log2 =
  let compareResponse =
        on (==) (fmap status)
      compareHeaders head1 head2 =
        on (==) (fmap referer) head1 head2
          && on (==) (fmap userAgent) head1 head2
          && on (==) (fmap range) head1 head2
      compareRequest req1 req2 =
        on (==) (fmap httpVersion) req1 req2
          && on (==) (fmap isSecure) req1 req2
          && on (==) (fmap method) req1 req2
          && on (==) (fmap path) req1 req2
          && on (==) (fmap queryString) req1 req2
          && on (==) (fmap bodyLength) req1 req2
          && on compareHeaders (fmap headers) req1 req2
   in on (==) logMessage log1 log2
        && on compareRequest (request . logData) log1 log2
        && on compareResponse (response . logData) log1 log2

instance Eq LogEntry where
  (==) = isMostlySameAs