wai-logger-0.3.1/0000755000000000000000000000000012147064531011741 5ustar0000000000000000wai-logger-0.3.1/LICENSE0000644000000000000000000000276512147064531012760 0ustar0000000000000000Copyright (c) 2009, IIJ Innovation Institute Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. wai-logger-0.3.1/Setup.hs0000644000000000000000000000005612147064531013376 0ustar0000000000000000import Distribution.Simple main = defaultMain wai-logger-0.3.1/wai-logger.cabal0000644000000000000000000000211112147064531014755 0ustar0000000000000000Name: wai-logger Version: 0.3.1 Author: Kazu Yamamoto Maintainer: Kazu Yamamoto License: BSD3 License-File: LICENSE Synopsis: A logging system for WAI Description: A logging system for WAI Category: Web, Yesod Cabal-Version: >= 1.6 Build-Type: Simple library GHC-Options: -Wall Exposed-Modules: Network.Wai.Logger Network.Wai.Logger.Format Network.Wai.Logger.Utils Build-Depends: base >= 4 && < 5 , blaze-builder , byteorder , bytestring , case-insensitive , date-cache >= 0.3 , fast-logger >= 0.3 , http-types , network , wai Source-Repository head Type: git Location: git://github.com/kazu-yamamoto/logger.git wai-logger-0.3.1/Network/0000755000000000000000000000000012147064531013372 5ustar0000000000000000wai-logger-0.3.1/Network/Wai/0000755000000000000000000000000012147064531014112 5ustar0000000000000000wai-logger-0.3.1/Network/Wai/Logger.hs0000644000000000000000000000441112147064531015665 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} -- | Logging system for WAI applications. -- -- Sample code: -- -- > {-# LANGUAGE OverloadedStrings #-} -- > module Main where -- > -- > import Blaze.ByteString.Builder (fromByteString) -- > import Control.Monad.IO.Class (liftIO) -- > import Data.ByteString.Char8 -- > import Network.HTTP.Types (status200) -- > import Network.Wai -- > import Network.Wai.Handler.Warp -- > import Network.Wai.Logger -- > -- > main :: IO () -- > main = do -- > aplogger <- stdoutApacheLoggerInit FromSocket True -- > run 3000 $ logapp aplogger -- > -- > logapp :: ApacheLogger -> Application -- > logapp aplogger req = do -- > let status = status200 -- > len = 4 -- > liftIO $ aplogger req status (Just len) -- > return $ ResponseBuilder status -- > [("Content-Type", "text/plain") -- > ,("Content-Length", pack (show len))] -- > $ fromByteString "PONG" module Network.Wai.Logger ( ApacheLogger , stdoutApacheLoggerInit , stdoutApacheLoggerInit2 , module Network.Wai.Logger.Format , module Network.Wai.Logger.Utils ) where import Control.Applicative import Network.HTTP.Types import Network.Wai import Network.Wai.Logger.Format import Network.Wai.Logger.Utils import System.Date.Cache import System.IO import System.Log.FastLogger -- | Apache style logger for WAI type ApacheLogger = Request -> Status -> Maybe Integer -> IO () -- | Obtaining Apache style logger to stdout stdoutApacheLoggerInit :: IPAddrSource -> Bool -- ^ Automatically flush on each logging? -> IO ApacheLogger stdoutApacheLoggerInit ipsrc autoFlash = stdoutLogger ipsrc <$> mkLogger autoFlash stdout -- | Obtaining Apache style logger to stdout stdoutApacheLoggerInit2 :: IPAddrSource -> Bool -- ^ Automatically flush on each logging? -> (DateCacheGetter, DateCacheCloser) -> IO ApacheLogger stdoutApacheLoggerInit2 ipsrc autoFlash dc = stdoutLogger ipsrc <$> mkLogger2 autoFlash stdout dc stdoutLogger :: IPAddrSource -> Logger -> ApacheLogger stdoutLogger ipsrc logger req status msiz = do date <- loggerDate logger loggerPutStr logger $ logmsg date where logmsg date = apacheFormat ipsrc date req status msiz wai-logger-0.3.1/Network/Wai/Logger/0000755000000000000000000000000012147064531015331 5ustar0000000000000000wai-logger-0.3.1/Network/Wai/Logger/Format.hs0000644000000000000000000000517512147064531017125 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} module Network.Wai.Logger.Format ( IPAddrSource(..) , apacheFormat -- * Builder , apacheFormatBuilder ) where import Blaze.ByteString.Builder import Blaze.ByteString.Builder.Char8 import Data.ByteString.Char8 (ByteString) import Data.CaseInsensitive import Data.List import Data.Maybe import Data.Monoid import Network.HTTP.Types import Network.Wai import Network.Wai.Logger.Utils import System.Log.FastLogger {-| Source from which the IP source address of the client is obtained. -} data IPAddrSource = -- | From the peer address of the HTTP connection. FromSocket -- | From X-Real-IP: or X-Forwarded-For: in the HTTP header. | FromHeader -- | Apache style log format. apacheFormat :: IPAddrSource -> ZonedDate -> Request -> Status -> Maybe Integer -> [LogStr] apacheFormat ipsrc tmstr req st msize = [ getSourceIP ipsrc req , LB " - - [" , LB tmstr , LB "] \"" , LB $ requestMethod req , LB " " , LB $ rawPathInfo req , LB " " , LS $ show . httpVersion $ req , LB "\" " , LS . show . statusCode $ st , LB " " , LS $ maybe "-" show msize , LB " \"" , LB $ lookupRequestField' "referer" req , LB "\" \"" , LB $ lookupRequestField' "user-agent" req , LB "\"\n" ] {-| Apache style log format with 'Builder'. This is experimental. This would replace 'apacheFormat' someday. -} apacheFormatBuilder :: IPAddrSource -> ZonedDate -> Request -> Status -> Maybe Integer -> Builder apacheFormatBuilder ipsrc tmstr req status msize = getSourceIP' ipsrc req +++ bs " - - [" +++ bs tmstr +++ bs "] \"" +++ bs (requestMethod req) +++ bs " " +++ bs (rawPathInfo req) +++ bs " " +++ st (show (httpVersion req)) +++ bs "\" " +++ st (show (statusCode status)) +++ bs " " +++ st (maybe "-" show msize) +++ bs " \"" +++ bs (lookupRequestField' "referer" req) +++ bs "\" \"" +++ bs (lookupRequestField' "user-agent" req) +++ bs "\"\n" where st = fromString bs = fromByteString (+++) = mappend lookupRequestField' :: CI ByteString -> Request -> ByteString lookupRequestField' k req = fromMaybe "" . lookup k $ requestHeaders req getSourceIP :: IPAddrSource -> Request -> LogStr getSourceIP FromSocket = LS . showSockAddr . remoteHost getSourceIP FromHeader = LB . getSource getSourceIP' :: IPAddrSource -> Request -> Builder getSourceIP' FromSocket = fromString . showSockAddr . remoteHost getSourceIP' FromHeader = fromByteString . getSource getSource :: Request -> ByteString getSource req = addr where maddr = find (\x -> fst x `elem` ["x-real-ip", "x-forwarded-for"]) hdrs addr = maybe "" snd maddr hdrs = requestHeaders req wai-logger-0.3.1/Network/Wai/Logger/Utils.hs0000644000000000000000000000324512147064531016771 0ustar0000000000000000module Network.Wai.Logger.Utils ( NumericAddress, showSockAddr ) where import Data.Bits import Data.Word import Network.Socket (SockAddr(..)) import System.ByteOrder import Text.Printf {-| A type for IP address in numeric string representation. -} type NumericAddress = String showIPv4 :: Word32 -> Bool -> NumericAddress showIPv4 w32 little | little = show b1 ++ "." ++ show b2 ++ "." ++ show b3 ++ "." ++ show b4 | otherwise = show b4 ++ "." ++ show b3 ++ "." ++ show b2 ++ "." ++ show b1 where t1 = w32 t2 = shift t1 (-8) t3 = shift t2 (-8) t4 = shift t3 (-8) b1 = t1 .&. 0x000000ff b2 = t2 .&. 0x000000ff b3 = t3 .&. 0x000000ff b4 = t4 .&. 0x000000ff showIPv6 :: (Word32,Word32,Word32,Word32) -> String showIPv6 (w1,w2,w3,w4) = printf "%x:%x:%x:%x:%x:%x:%x:%x" s1 s2 s3 s4 s5 s6 s7 s8 where (s1,s2) = split16 w1 (s3,s4) = split16 w2 (s5,s6) = split16 w3 (s7,s8) = split16 w4 split16 w = (h1,h2) where h1 = shift w (-16) .&. 0x0000ffff h2 = w .&. 0x0000ffff {-| Convert 'SockAddr' to 'NumericAddress'. If the address is an IPv4-embedded IPv6 address, the IPv4 is extracted. -} -- HostAddr is network byte order. -- HostAddr6 is host byte order. showSockAddr :: SockAddr -> NumericAddress showSockAddr (SockAddrInet _ addr4) = showIPv4 addr4 (byteOrder == LittleEndian) showSockAddr (SockAddrInet6 _ _ (0,0,0x0000ffff,addr4) _) = showIPv4 addr4 False showSockAddr (SockAddrInet6 _ _ (0,0,0,1) _) = "::1" showSockAddr (SockAddrInet6 _ _ addr6 _) = showIPv6 addr6 showSockAddr _ = "unknownSocket"