How can i add a specific representation of the request and response body in a request logger? I would like to be able to have some typeclass
that allows me to achieve this representation. In the Network.Wai.Middleware.RequestLogger.JSON
I can see how a request logger is implemented.
formatAsJSONWithHeaders :: OutputFormatterWithDetailsAndHeaders
formatAsJSONWithHeaders date req status resSize duration reqBody res resHeaders =
toLogStr (encode $
object
[ "request" .= requestToJSON duration req reqBody
, "response" .= object
[ "status" .= statusCode status
, "size" .= resSize
, "headers" .= responseHeadersToJSON resHeaders
, "body" .=
if statusCode status >= 400
then Just . decodeUtf8With lenientDecode . toStrict . BB.toLazyByteString $ res
else Nothing
]
, "time" .= decodeUtf8With lenientDecode date
]) <> "\n"
requestToJSON :: NominalDiffTime -> Request -> [S8.ByteString] -> Value
requestToJSON duration req reqBody =
object
[ "method" .= decodeUtf8With lenientDecode (requestMethod req)
, "path" .= decodeUtf8With lenientDecode (rawPathInfo req)
, "queryString" .= map queryItemToJSON (queryString req)
, "durationMs" .= (readAsDouble . printf "%.2f" . rationalToDouble $ toRational duration * 1000)
, "size" .= requestBodyLengthToJSON (requestBodyLength req)
, "body" .= decodeUtf8With lenientDecode (S8.concat reqBody)
, "remoteHost" .= sockToJSON (remoteHost req)
, "httpVersion" .= httpVersionToJSON (httpVersion req)
, "headers" .= requestHeadersToJSON (requestHeaders req)
]
where
rationalToDouble :: Rational -> Double
rationalToDouble = fromRational
So if I were to get the request:
new_user : { "email": "foo", "password": "bar" }
I would like to email just:
new_user : { "email": "foo", "password": "" }
and i do this via some typeclass:
class LogRepr body where
toLogRepr :: body -> Value -- Some monoidal text
instance LogRepr NewUser where
toLogRepr nu = object
[ "new_user" .=
object
[ "email" .= email nu
]
]
This would allow me to easily use the toJSON and FromJSON of types that i don't want to modify the default behavior for. Is it also possible to modify this so I can add some arbitrary context to this when my application is running like a "message" field or "activity" field.