Logging TH functions and a minor bugfix

This commit is contained in:
Michael Snoyman 2011-04-09 23:12:09 +03:00
parent 410aec472f
commit 1948a9a429
4 changed files with 78 additions and 19 deletions

View File

@ -1,3 +1,4 @@
{-# LANGUAGE TemplateHaskell #-}
module Yesod.Core module Yesod.Core
( -- * Type classes ( -- * Type classes
Yesod (..) Yesod (..)
@ -16,6 +17,11 @@ module Yesod.Core
-- * Logging -- * Logging
, LogLevel (..) , LogLevel (..)
, formatLogMessage , formatLogMessage
, logDebug
, logInfo
, logWarn
, logError
, logOther
-- * Misc -- * Misc
, yesodVersion , yesodVersion
, yesodRender , yesodRender
@ -33,3 +39,35 @@ import Yesod.Dispatch
import Yesod.Handler import Yesod.Handler
import Yesod.Request import Yesod.Request
import Yesod.Widget import Yesod.Widget
import Language.Haskell.TH.Syntax
import Data.Text (Text)
logTH :: LogLevel -> Q Exp
logTH level =
[|messageLoggerHandler $(qLocation >>= liftLoc) $(lift level)|]
where
liftLoc :: Loc -> Q Exp
liftLoc (Loc a b c d e) = [|Loc $(lift a) $(lift b) $(lift c) $(lift d) $(lift e)|]
-- | Generates a function that takes a 'Text' and logs a 'LevelDebug' message. Usage:
--
-- > $(logDebug) "This is a debug log message"
logDebug :: Q Exp
logDebug = logTH LevelDebug
-- | See 'logDebug'
logInfo :: Q Exp
logInfo = logTH LevelInfo
-- | See 'logDebug'
logWarn :: Q Exp
logWarn = logTH LevelWarn
-- | See 'logDebug'
logError :: Q Exp
logError = logTH LevelError
-- | Generates a function that takes a 'Text' and logs a 'LevelOther' message. Usage:
--
-- > $(logOther "My new level") "This is a log message"
logOther :: Text -> Q Exp
logOther = logTH . LevelOther

View File

@ -3,6 +3,7 @@
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
-- | The basic typeclass for a Yesod application. -- | The basic typeclass for a Yesod application.
module Yesod.Internal.Core module Yesod.Internal.Core
( -- * Type classes ( -- * Type classes
@ -22,6 +23,7 @@ module Yesod.Internal.Core
-- * Logging -- * Logging
, LogLevel (..) , LogLevel (..)
, formatLogMessage , formatLogMessage
, messageLoggerHandler
-- * Misc -- * Misc
, yesodVersion , yesodVersion
, yesodRender , yesodRender
@ -53,7 +55,7 @@ import qualified Text.Blaze.Html5 as TBH
import Data.Text.Lazy.Builder (toLazyText) import Data.Text.Lazy.Builder (toLazyText)
import Data.Text.Lazy.Encoding (encodeUtf8) import Data.Text.Lazy.Encoding (encodeUtf8)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (MonadIO (liftIO))
import Web.Cookie (parseCookies) import Web.Cookie (parseCookies)
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Time import Data.Time
@ -70,6 +72,7 @@ import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO import qualified Data.Text.Lazy.IO
import qualified System.IO import qualified System.IO
import qualified Data.Text.Lazy.Builder as TB import qualified Data.Text.Lazy.Builder as TB
import Language.Haskell.TH.Syntax (Loc (..), Lift (..))
#if GHC7 #if GHC7
#define HAMLET hamlet #define HAMLET hamlet
@ -245,29 +248,44 @@ class RenderRoute (Route a) => Yesod a where
-- | Send a message to the log. By default, prints to stderr. -- | Send a message to the log. By default, prints to stderr.
messageLogger :: a messageLogger :: a
-> Loc -- ^ position in source code
-> LogLevel -> LogLevel
-> Text -- ^ source
-> Text -- ^ message -> Text -- ^ message
-> IO () -> IO ()
messageLogger _ level src msg = messageLogger _ loc level msg =
formatLogMessage level src msg >>= formatLogMessage loc level msg >>=
Data.Text.Lazy.IO.hPutStrLn System.IO.stderr Data.Text.Lazy.IO.hPutStrLn System.IO.stderr
messageLoggerHandler :: (Yesod m, MonadIO mo)
=> Loc -> LogLevel -> Text -> GGHandler s m mo ()
messageLoggerHandler loc level msg = do
y <- getYesod
liftIO $ messageLogger y loc level msg
data LogLevel = LevelDebug | LevelInfo | LevelWarn | LevelError | LevelOther Text data LogLevel = LevelDebug | LevelInfo | LevelWarn | LevelError | LevelOther Text
deriving (Eq, Show, Read, Ord) deriving (Eq, Show, Read, Ord)
formatLogMessage :: LogLevel instance Lift LogLevel where
-> Text -- ^ source lift LevelDebug = [|LevelDebug|]
lift LevelInfo = [|LevelInfo|]
lift LevelWarn = [|LevelWarn|]
lift LevelError = [|LevelError|]
lift (LevelOther x) = [|LevelOther $ TS.pack $(lift $ TS.unpack x)|]
formatLogMessage :: Loc
-> LogLevel
-> Text -- ^ message -> Text -- ^ message
-> IO TL.Text -> IO TL.Text
formatLogMessage level src msg = do formatLogMessage loc level msg = do
now <- getCurrentTime now <- getCurrentTime
return $ TB.toLazyText $ return $ TB.toLazyText $
TB.fromText (TS.pack $ show now) TB.fromText (TS.pack $ show now)
`mappend` TB.fromText ": " `mappend` TB.fromText ": "
`mappend` TB.fromText (TS.pack $ show level) `mappend` TB.fromText (TS.pack $ show level)
`mappend` TB.fromText "@(" `mappend` TB.fromText "@("
`mappend` TB.fromText src `mappend` TB.fromText (TS.pack $ loc_filename loc)
`mappend` TB.fromText ":"
`mappend` TB.fromText (TS.pack $ show $ fst $ loc_start loc)
`mappend` TB.fromText ") " `mappend` TB.fromText ") "
`mappend` TB.fromText msg `mappend` TB.fromText msg

View File

@ -279,11 +279,11 @@ mkSubsiteExp segments (SinglePiece _:pieces) frontVars x = do
fsp <- [|fromSinglePiece|] fsp <- [|fromSinglePiece|]
let exp' = CaseE (fsp `AppE` VarE next) let exp' = CaseE (fsp `AppE` VarE next)
[ Match [ Match
(ConP (mkName "Left") [WildP]) (ConP (mkName "Nothing") [])
(NormalB nothing) (NormalB nothing)
[] []
, Match , Match
(ConP (mkName "Right") [VarP next']) (ConP (mkName "Just") [VarP next'])
(NormalB innerExp) (NormalB innerExp)
[] []
] ]

View File

@ -1,11 +1,10 @@
{-# LANGUAGE QuasiQuotes, TypeFamilies, OverloadedStrings #-} {-# LANGUAGE QuasiQuotes, TypeFamilies, OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TemplateHaskell #-}
import Yesod.Core import Yesod.Core
import Yesod.Dispatch import Network.Wai.Handler.Warp (run)
import Yesod.Content import Data.Text (unpack)
import Yesod.Handler
import Network.Wai.Handler.Warp (runEx)
data Subsite = Subsite String data Subsite = Subsite String
@ -14,16 +13,18 @@ mkYesodSub "Subsite" [] [$parseRoutes|
/multi/*Strings SubMultiR /multi/*Strings SubMultiR
|] |]
getSubRootR :: GHandler Subsite m RepPlain getSubRootR :: Yesod m => GHandler Subsite m RepPlain
getSubRootR = do getSubRootR = do
Subsite s <- getYesodSub Subsite s <- getYesodSub
tm <- getRouteToMaster tm <- getRouteToMaster
render <- getUrlRender render <- getUrlRender
return $ RepPlain $ toContent $ "Hello Sub World: " ++ s ++ ". " ++ render (tm SubRootR) $(logDebug) "I'm in SubRootR"
return $ RepPlain $ toContent $ "Hello Sub World: " ++ s ++ ". " ++ unpack (render (tm SubRootR))
handleSubMultiR :: Strings -> GHandler Subsite m RepPlain handleSubMultiR :: Yesod m => Strings -> GHandler Subsite m RepPlain
handleSubMultiR x = do handleSubMultiR x = do
Subsite y <- getYesodSub Subsite y <- getYesodSub
$(logInfo) "In SubMultiR"
return . RepPlain . toContent . show $ (x, y) return . RepPlain . toContent . show $ (x, y)
data HelloWorld = HelloWorld { getSubsite :: String -> Subsite } data HelloWorld = HelloWorld { getSubsite :: String -> Subsite }
@ -33,5 +34,7 @@ mkYesod "HelloWorld" [$parseRoutes|
|] |]
instance Yesod HelloWorld where approot _ = "" instance Yesod HelloWorld where approot _ = ""
-- getRootR :: GHandler HelloWorld HelloWorld RepPlain -- FIXME remove type sig -- getRootR :: GHandler HelloWorld HelloWorld RepPlain -- FIXME remove type sig
getRootR = return $ RepPlain "Hello World" getRootR = do
main = toWaiApp (HelloWorld Subsite) >>= runEx print 3000 $(logOther "HAHAHA") "Here I am"
return $ RepPlain "Hello World"
main = toWaiApp (HelloWorld Subsite) >>= run 3000