packages feed

wai-extra 3.0.26.1 → 3.0.27

raw patch · 4 files changed

+95/−8 lines, 4 files

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Changelog for wai-extra +## 3.0.27++* Add custom request log formatter which includes response headers [#762](https://github.com/yesodweb/wai/pull/762)+ ## 3.0.26.1  * When available, supply the response size to custom loggers
Network/Wai/Middleware/RequestLogger.hs view
@@ -14,6 +14,7 @@     , OutputFormat (..)     , OutputFormatter     , OutputFormatterWithDetails+    , OutputFormatterWithDetailsAndHeaders     , Destination (..)     , Callback     , IPAddrSource (..)@@ -49,15 +50,43 @@ import Network.Wai.Header (contentLength) import Data.Text.Encoding (decodeUtf8') -data OutputFormat = Apache IPAddrSource-                  | Detailed Bool -- ^ use colors?-                  | CustomOutputFormat OutputFormatter-                  | CustomOutputFormatWithDetails OutputFormatterWithDetails+data OutputFormat+  = Apache IPAddrSource+  | Detailed Bool -- ^ use colors?+  | CustomOutputFormat OutputFormatter+  | CustomOutputFormatWithDetails OutputFormatterWithDetails+  | CustomOutputFormatWithDetailsAndHeaders OutputFormatterWithDetailsAndHeaders  type OutputFormatter = ZonedDate -> Request -> Status -> Maybe Integer -> LogStr-type OutputFormatterWithDetails =-  ZonedDate -> Request -> Status -> Maybe Integer -> NominalDiffTime -> [S8.ByteString] -> B.Builder -> LogStr +type OutputFormatterWithDetails+   = ZonedDate+  -> Request+  -> Status+  -> Maybe Integer+  -> NominalDiffTime+  -> [S8.ByteString]+  -> B.Builder+  -> LogStr++-- | Same as @OutputFormatterWithDetails@ but with response headers included+--+-- This is useful if you wish to include arbitrary application data in your+-- logs, e.g., an authenticated user ID, which you would set in a response+-- header in your application and retrieve in the log formatter.+--+-- @since 3.0.27+type OutputFormatterWithDetailsAndHeaders+   = ZonedDate -- ^ When the log message was generated+  -> Request -- ^ The WAI request+  -> Status -- ^ HTTP status code+  -> Maybe Integer -- ^ Response size+  -> NominalDiffTime -- ^ Duration of the request+  -> [S8.ByteString] -- ^ The request body+  -> B.Builder -- ^ Raw response+  -> [Header] -- ^ The response headers+  -> LogStr+ data Destination = Handle Handle                  | Logger LoggerSet                  | Callback Callback@@ -108,6 +137,9 @@         CustomOutputFormatWithDetails formatter -> do             getdate <- getDateGetter flusher             return $ customMiddlewareWithDetails callbackAndFlush getdate formatter+        CustomOutputFormatWithDetailsAndHeaders formatter -> do+            getdate <- getDateGetter flusher+            return $ customMiddlewareWithDetailsAndHeaders callbackAndFlush getdate formatter  apacheMiddleware :: ApacheLoggerActions -> Middleware apacheMiddleware ala app req sendResponse = app req $ \res -> do@@ -138,6 +170,24 @@       readIORef builderIO     return rspRcv +customMiddlewareWithDetailsAndHeaders :: Callback -> IO ZonedDate -> OutputFormatterWithDetailsAndHeaders -> Middleware+customMiddlewareWithDetailsAndHeaders cb getdate formatter app req sendResponse = do+  (req', reqBody) <- getRequestBody req+  t0 <- getCurrentTime+  app req' $ \res -> do+    t1 <- getCurrentTime+    date <- liftIO getdate+    let msize = contentLength (responseHeaders res)+    builderIO <- newIORef $ B.byteString ""+    res' <- recordChunks builderIO res+    rspRcv <- sendResponse res'+    _ <- do+      rawResponse <- readIORef builderIO+      let status = responseStatus res'+          duration = t1 `diffUTCTime` t0+          resHeaders = responseHeaders res'+      liftIO . cb $ formatter date req' status msize duration reqBody rawResponse resHeaders+    return rspRcv -- | Production request logger middleware. -- -- This uses the 'Apache' logging format, and takes IP addresses for clients from
Network/Wai/Middleware/RequestLogger/JSON.hs view
@@ -1,7 +1,10 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE CPP #-} -module Network.Wai.Middleware.RequestLogger.JSON (formatAsJSON) where+module Network.Wai.Middleware.RequestLogger.JSON+  ( formatAsJSON+  , formatAsJSONWithHeaders+  ) where  import qualified Data.ByteString.Builder as BB (toLazyByteString) import Data.ByteString.Lazy (toStrict)@@ -40,6 +43,30 @@       , "time"     .= decodeUtf8With lenientDecode date       ]) <> "\n" +-- | Same as @formatAsJSON@ but with response headers included+--+-- This is useful for passing arbitrary data from your application out to the+-- WAI layer for it to be logged, but you may need to be careful to+-- subsequently redact any headers which may contain sensitive data.+--+-- @since 3.0.27+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"+ word32ToHostAddress :: Word32 -> Text word32ToHostAddress = T.intercalate "." . map (T.pack . show) . fromIPv4 . fromHostAddress @@ -88,6 +115,12 @@ requestHeadersToJSON = toJSON . map hToJ where   -- Redact cookies   hToJ ("Cookie", _) = toJSON ("Cookie" :: Text, "-RDCT-" :: Text)+  hToJ hd = headerToJSON hd++responseHeadersToJSON :: [Header] -> Value+responseHeadersToJSON = toJSON . map hToJ where+  -- Redact cookies+  hToJ ("Set-Cookie", _) = toJSON ("Set-Cookie" :: Text, "-RDCT-" :: Text)   hToJ hd = headerToJSON hd  headerToJSON :: Header -> Value
wai-extra.cabal view
@@ -1,5 +1,5 @@ Name:                wai-extra-Version:             3.0.26.1+Version:             3.0.27 Synopsis:            Provides some basic WAI handlers and middleware. description:   Provides basic WAI handler and middleware functionality: