@@ -28,28 +28,36 @@ module Katip.Monadic
28 , AnyLogContext
28 , AnyLogContext
29 , LogContexts
29 , LogContexts
30 , liftPayload
30 , liftPayload
32+ -- * LogT - Utility transformer that provides Katip and KatipContext instances
34-------------------------------------------------------------------------------
39-------------------------------------------------------------------------------
40+import Control.Applicative
41+import Control.Monad.Base
35import Control.Monad.Catch
42import Control.Monad.Catch
36−import Control.Monad.Trans.Class
43+import Control.Monad.Error.Class
44+import Control.Monad.IO.Class
45+import Control.Monad.Reader
46+import Control.Monad.State
37import Control.Monad.Trans.Either (EitherT)
47import Control.Monad.Trans.Either (EitherT)
38import Control.Monad.Trans.Except (ExceptT)
48import Control.Monad.Trans.Except (ExceptT)
39import Control.Monad.Trans.Identity (IdentityT)
49import Control.Monad.Trans.Identity (IdentityT)
40import Control.Monad.Trans.List (ListT)
50import Control.Monad.Trans.List (ListT)
41import Control.Monad.Trans.Maybe (MaybeT)
51import Control.Monad.Trans.Maybe (MaybeT)
42−import Control.Monad.Trans.Reader (ReaderT)
43import Control.Monad.Trans.Resource (ResourceT)
52import Control.Monad.Trans.Resource (ResourceT)
44import Control.Monad.Trans.RWS (RWST)
53import Control.Monad.Trans.RWS (RWST)
45import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST)
54import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST)
46−import Control.Monad.Trans.State (StateT)
47import qualified Control.Monad.Trans.State.Strict as Strict (StateT)
55import qualified Control.Monad.Trans.State.Strict as Strict (StateT)
48−import Control.Monad.Trans.Writer (WriterT)
49import qualified Control.Monad.Trans.Writer.Strict as Strict (WriterT)
56import qualified Control.Monad.Trans.Writer.Strict as Strict (WriterT)
57+import Control.Monad.Writer
50import Data.Aeson
58import Data.Aeson
51import qualified Data.HashMap.Strict as HM
59import qualified Data.HashMap.Strict as HM
52−import Data.Monoid
60+import Data.Monoid as M
53import Data.Text (Text)
61import Data.Text (Text)
54import Language.Haskell.TH
62import Language.Haskell.TH
55-------------------------------------------------------------------------------
63-------------------------------------------------------------------------------
@@ -179,4 +187,69 @@ logExceptionM
179logExceptionM action sev = action `catchAll` \e -> f e >> throwM e
187logExceptionM action sev = action `catchAll` \e -> f e >> throwM e
181 f e = logFM sev (msg e)
189 f e = logFM sev (msg e)
182− msg e = ls ("An exception has occured: " :: Text) <> showLS e
190+ msg e = ls ("An exception has occured: " :: Text) M.<> showLS e
193+-------------------------------------------------------------------------------
194+-- | Provides a simple transformer that defines a 'KatipContext'
195+-- instance for a fixed namespace and context. You will typically only
196+-- use this if you are forced to run in IO but still want to have your
197+-- log context. This is the slightly more powerful version of KatipT
198+-- in that it provides KatipContext instead of just Katip. For instance:
201+-- threadWithLogging = do
203+-- ctx <- getKatipContext
204+-- ns <- getKatipNamespace
205+-- forkIO $ runLogT le ctx ns $ do
206+-- $(logTM) InfoS "Look, I can log in IO and retain context!"
209+newtype LogT m a = LogT {
210+ unLogT :: ReaderT LogTState m a
211+ } deriving ( Functor
229+data LogTState = LogTState {
230+ ltsLogEnv :: !LogEnv
231+ , ltsContext :: !LogContexts
232+ , ltsNamespace :: !Namespace
235+-- Reader is a passthrough. We don't expose our internal reader so as not to conflict
236+instance (MonadReader r m) => MonadReader r (LogT m) where
238+ local f (LogT (ReaderT m)) = LogT $ ReaderT $ \r ->
242+instance (MonadIO m) => Katip (LogT m) where
243+ getLogEnv = LogT $ ReaderT $ \lts -> return (ltsLogEnv lts)
246+instance (MonadIO m) => KatipContext (LogT m) where
247+ getKatipContext = LogT $ ReaderT $ \lts -> return (ltsContext lts)
248+ getKatipNamespace = LogT $ ReaderT $ \lts -> return (ltsNamespace lts)
251+-------------------------------------------------------------------------------
252+runLogT :: (LogItem c) => LogEnv -> c -> Namespace -> LogT m a -> m a
253+runLogT le ctx ns = flip runReaderT lts . unLogT
255+ lts = LogTState le (liftPayload ctx) ns