{-| Module : Game.GoreAndAsh.Module Description : Module that contains monadic and arrow API of logging module. Copyright : (c) Anton Gushcha, 2015-2016 License : BSD3 Maintainer : ncrashed@gmail.com Stability : experimental Portability : POSIX Module that contains monadic and arrow API of logging module. -} module Game.GoreAndAsh.Logging.API( LoggingMonad(..) , loggingSetFile -- * Arrow API , logA , logALn , logE , logELn -- ** Every frame , logDebugA , logInfoA , logWarnA , logErrorA -- ** Event based , logDebugE , logInfoE , logWarnE , logErrorE -- ** Event tracing , traceEvent , traceEventShow ) where import Control.Monad.Extra (whenJust) import Control.Monad.State.Strict import Control.Wire import Data.Text import Prelude hiding (id, (.)) import qualified Data.HashMap.Strict as H import qualified Data.HashSet as HS import qualified Data.Sequence as S import System.IO as IO import TextShow import Game.GoreAndAsh import Game.GoreAndAsh.Logging.State import Game.GoreAndAsh.Logging.Module -- | Low level API for module class MonadIO m => LoggingMonad m where -- | Put message to the console. putMsgM :: LoggingLevel -> Text -> m () -- | Put message and new line to the console. putMsgLnM :: LoggingLevel -> Text -> m () -- | Setting current logging file handler loggingSetHandle :: IO.Handle -> m () -- | Setting allowed sinks for given logging level. -- -- By default all messages are passed into file and console. loggingSetFilter :: LoggingLevel -> [LoggingSink] -> m () instance {-# OVERLAPPING #-} MonadIO m => LoggingMonad (LoggingT s m) where putMsgM l t = do cntx <- get let newMsgs = case S.viewr $ loggingMsgs cntx of S.EmptyR -> loggingMsgs cntx S.|> (l, t) (s' S.:> (l', t')) -> s' S.|> (l', t' <> t) put $ cntx { loggingMsgs = newMsgs } putMsgLnM l t = do cntx <- get put $ cntx { loggingMsgs = loggingMsgs cntx S.|> (l, t) } loggingSetHandle h = do cntx <- get whenJust (loggingFile cntx) $ liftIO . IO.hClose put $ cntx { loggingFile = Just h } loggingSetFilter l ss = do cntx <- get let lfilter = case l `H.lookup` loggingFilter cntx of Nothing -> H.insert l (HS.fromList ss) . loggingFilter $ cntx Just ss' -> H.insert l (HS.fromList ss `HS.union` ss') . loggingFilter $ cntx put $ cntx { loggingFilter = lfilter } instance {-# OVERLAPPABLE #-} (MonadIO (mt m), LoggingMonad m, MonadTrans mt) => LoggingMonad (mt m) where putMsgM a b = lift $ putMsgM a b putMsgLnM a b = lift $ putMsgLnM a b loggingSetHandle = lift . loggingSetHandle loggingSetFilter a b = lift $ loggingSetFilter a b -- | Put message to console on every frame without newline logA :: LoggingMonad m => LoggingLevel -> GameWire m Text () logA l = liftGameMonad1 (putMsgM l) -- | Put message to console on every frame logALn :: LoggingMonad m => LoggingLevel -> GameWire m Text () logALn l = liftGameMonad1 (putMsgLnM l) -- | Put message to console on event without newline logE :: LoggingMonad m => LoggingLevel -> GameWire m (Event Text) (Event ()) logE l = liftGameMonadEvent1 (putMsgM l) -- | Put message to console on event logELn :: LoggingMonad m => LoggingLevel -> GameWire m (Event Text) (Event ()) logELn l = liftGameMonadEvent1 (putMsgLnM l) -- | Put info msg to console logDebugA :: LoggingMonad m => GameWire m Text () logDebugA = logALn LogDebug . arr ("Debug: " <>) -- | Put info msg to console logInfoA :: LoggingMonad m => GameWire m Text () logInfoA = logALn LogInfo . arr ("Info: " <>) -- | Put warn msg to console logWarnA :: LoggingMonad m => GameWire m Text () logWarnA = logALn LogWarn . arr ("Warning: " <>) -- | Put error msg to console logErrorA :: LoggingMonad m => GameWire m Text () logErrorA = logALn LogError . arr ("Error: " <>) -- | Put info msg to console on event logDebugE :: LoggingMonad m => GameWire m (Event Text) (Event ()) logDebugE = logELn LogDebug . mapE ("Debug: " <>) -- | Put info msg to console on event logInfoE :: LoggingMonad m => GameWire m (Event Text) (Event ()) logInfoE = logELn LogInfo . mapE ("Info: " <>) -- | Put warn msg to console on event logWarnE :: LoggingMonad m => GameWire m (Event Text) (Event ()) logWarnE = logELn LogWarn . mapE ("Warning: " <>) -- | Put error msg to console on event logErrorE :: LoggingMonad m => GameWire m (Event Text) (Event ()) logErrorE = logELn LogError . mapE ("Error: " <>) -- | Prints event with given function traceEvent :: LoggingMonad m => (a -> Text) -> GameWire m (Event a) (Event ()) traceEvent f = logELn LogDebug . mapE f -- | Prints event traceEventShow :: (TextShow a, LoggingMonad m) => GameWire m (Event a) (Event ()) traceEventShow = traceEvent showt -- | Helper to set logging file as local path loggingSetFile :: (LoggingMonad m) => FilePath -- ^ Path to logging file -> Bool -- ^ If 'False', rewrites contents of the file, if 'True' opens in append mode -> m () loggingSetFile fname isAppend = do h <- liftIO $ IO.openFile fname $ if isAppend then AppendMode else WriteMode loggingSetHandle h