katip 0.1.1.0 → 0.2.0.0
raw patch · 11 files changed
+406/−88 lines, 11 filesdep +microlensdep +microlens-thdep −lensdep −lens-aesondep ~mtldep ~transformersdep ~transformers-basePVP ok
version bump matches the API change (PVP)
Dependencies added: microlens, microlens-th
Dependencies removed: lens, lens-aeson
Dependency ranges changed: mtl, transformers, transformers-base, unordered-containers
API changes (from Hackage documentation)
- Katip: _itemApp :: Item a -> Namespace
- Katip: _itemEnv :: Item a -> Environment
- Katip: _itemHost :: Item a -> HostName
- Katip: _itemLoc :: Item a -> Maybe Loc
- Katip: _itemMessage :: Item a -> LogStr
- Katip: _itemNamespace :: Item a -> Namespace
- Katip: _itemPayload :: Item a -> a
- Katip: _itemProcess :: Item a -> ProcessID
- Katip: _itemSeverity :: Item a -> Severity
- Katip: _itemThread :: Item a -> ThreadIdText
- Katip: _itemTime :: Item a -> UTCTime
- Katip: _logEnvEnv :: LogEnv -> Environment
- Katip: _logEnvHost :: LogEnv -> HostName
- Katip: _logEnvNs :: LogEnv -> Namespace
- Katip: _logEnvPid :: LogEnv -> ProcessID
- Katip: _logEnvScribes :: LogEnv -> Map Text Scribe
- Katip: _logEnvTimer :: LogEnv -> IO UTCTime
- Katip: getEnvironment :: Environment -> Text
- Katip: getThreadIdText :: ThreadIdText -> Text
- Katip: liPush :: Scribe -> forall a. LogItem a => Item a -> IO ()
- Katip: logEnvNs :: Lens' LogEnv Namespace
- Katip: severityText :: Prism' Text Severity
- Katip: unKatipT :: KatipT m a -> ReaderT LogEnv m a
- Katip: unLogStr :: LogStr -> Builder
- Katip: unNamespace :: Namespace -> [Text]
- Katip.Core: _itemApp :: Item a -> Namespace
- Katip.Core: _itemEnv :: Item a -> Environment
- Katip.Core: _itemHost :: Item a -> HostName
- Katip.Core: _itemLoc :: Item a -> Maybe Loc
- Katip.Core: _itemMessage :: Item a -> LogStr
- Katip.Core: _itemNamespace :: Item a -> Namespace
- Katip.Core: _itemPayload :: Item a -> a
- Katip.Core: _itemProcess :: Item a -> ProcessID
- Katip.Core: _itemSeverity :: Item a -> Severity
- Katip.Core: _itemThread :: Item a -> ThreadIdText
- Katip.Core: _itemTime :: Item a -> UTCTime
- Katip.Core: _logEnvEnv :: LogEnv -> Environment
- Katip.Core: _logEnvHost :: LogEnv -> HostName
- Katip.Core: _logEnvNs :: LogEnv -> Namespace
- Katip.Core: _logEnvPid :: LogEnv -> ProcessID
- Katip.Core: _logEnvScribes :: LogEnv -> Map Text Scribe
- Katip.Core: _logEnvTimer :: LogEnv -> IO UTCTime
- Katip.Core: getEnvironment :: Environment -> Text
- Katip.Core: getLocJs :: LocJs -> Loc
- Katip.Core: getProcessIDJs :: ProcessIDJs -> ProcessID
- Katip.Core: getThreadIdText :: ThreadIdText -> Text
- Katip.Core: instance (Katip m, Monoid s) => Katip (WriterT s m)
- Katip.Core: instance Applicative m => Applicative (KatipT m)
- Katip.Core: instance Bounded Severity
- Katip.Core: instance Constructor C1_0Environment
- Katip.Core: instance Constructor C1_0Item
- Katip.Core: instance Constructor C1_0LogStr
- Katip.Core: instance Constructor C1_0Namespace
- Katip.Core: instance Constructor C1_0Severity
- Katip.Core: instance Constructor C1_0Verbosity
- Katip.Core: instance Constructor C1_1Severity
- Katip.Core: instance Constructor C1_1Verbosity
- Katip.Core: instance Constructor C1_2Severity
- Katip.Core: instance Constructor C1_2Verbosity
- Katip.Core: instance Constructor C1_3Severity
- Katip.Core: instance Constructor C1_3Verbosity
- Katip.Core: instance Constructor C1_4Severity
- Katip.Core: instance Constructor C1_5Severity
- Katip.Core: instance Constructor C1_6Severity
- Katip.Core: instance Constructor C1_7Severity
- Katip.Core: instance Datatype D1Environment
- Katip.Core: instance Datatype D1Item
- Katip.Core: instance Datatype D1LogStr
- Katip.Core: instance Datatype D1Namespace
- Katip.Core: instance Datatype D1Severity
- Katip.Core: instance Datatype D1Verbosity
- Katip.Core: instance Enum Severity
- Katip.Core: instance Enum Verbosity
- Katip.Core: instance Eq Environment
- Katip.Core: instance Eq Namespace
- Katip.Core: instance Eq Severity
- Katip.Core: instance Eq ThreadIdText
- Katip.Core: instance Eq Verbosity
- Katip.Core: instance FromJSON Environment
- Katip.Core: instance FromJSON LocJs
- Katip.Core: instance FromJSON LogStr
- Katip.Core: instance FromJSON Namespace
- Katip.Core: instance FromJSON ProcessIDJs
- Katip.Core: instance FromJSON Severity
- Katip.Core: instance FromJSON ThreadIdText
- Katip.Core: instance FromJSON a => FromJSON (Item a)
- Katip.Core: instance Functor Item
- Katip.Core: instance Functor m => Functor (KatipT m)
- Katip.Core: instance Generic (Item a)
- Katip.Core: instance Generic Environment
- Katip.Core: instance Generic LogStr
- Katip.Core: instance Generic Namespace
- Katip.Core: instance Generic Severity
- Katip.Core: instance Generic Verbosity
- Katip.Core: instance IsString Environment
- Katip.Core: instance IsString LogStr
- Katip.Core: instance IsString Namespace
- Katip.Core: instance Katip m => Katip (EitherT s m)
- Katip.Core: instance Katip m => Katip (ExceptT s m)
- Katip.Core: instance Katip m => Katip (MaybeT m)
- Katip.Core: instance Katip m => Katip (ReaderT s m)
- Katip.Core: instance Katip m => Katip (ResourceT m)
- Katip.Core: instance Katip m => Katip (StateT s m)
- Katip.Core: instance Lift Namespace
- Katip.Core: instance Lift Severity
- Katip.Core: instance Lift Verbosity
- Katip.Core: instance LogItem ()
- Katip.Core: instance LogItem SimpleLogPayload
- Katip.Core: instance Monad m => Monad (KatipT m)
- Katip.Core: instance MonadBase b m => MonadBase b (KatipT m)
- Katip.Core: instance MonadBaseControl b m => MonadBaseControl b (KatipT m)
- Katip.Core: instance MonadCatch m => MonadCatch (KatipT m)
- Katip.Core: instance MonadIO m => Katip (KatipT m)
- Katip.Core: instance MonadIO m => MonadIO (KatipT m)
- Katip.Core: instance MonadMask m => MonadMask (KatipT m)
- Katip.Core: instance MonadThrow m => MonadThrow (KatipT m)
- Katip.Core: instance MonadTrans KatipT
- Katip.Core: instance MonadTransControl KatipT
- Katip.Core: instance Monoid LogStr
- Katip.Core: instance Monoid Namespace
- Katip.Core: instance Monoid PayloadSelection
- Katip.Core: instance Monoid Scribe
- Katip.Core: instance Monoid SimpleLogPayload
- Katip.Core: instance Ord Environment
- Katip.Core: instance Ord Namespace
- Katip.Core: instance Ord Severity
- Katip.Core: instance Ord ThreadIdText
- Katip.Core: instance Ord Verbosity
- Katip.Core: instance Read Environment
- Katip.Core: instance Read Namespace
- Katip.Core: instance Read Severity
- Katip.Core: instance Read Verbosity
- Katip.Core: instance Selector S1_0_0Environment
- Katip.Core: instance Selector S1_0_0Item
- Katip.Core: instance Selector S1_0_0LogStr
- Katip.Core: instance Selector S1_0_0Namespace
- Katip.Core: instance Selector S1_0_10Item
- Katip.Core: instance Selector S1_0_1Item
- Katip.Core: instance Selector S1_0_2Item
- Katip.Core: instance Selector S1_0_3Item
- Katip.Core: instance Selector S1_0_4Item
- Katip.Core: instance Selector S1_0_5Item
- Katip.Core: instance Selector S1_0_6Item
- Katip.Core: instance Selector S1_0_7Item
- Katip.Core: instance Selector S1_0_8Item
- Katip.Core: instance Selector S1_0_9Item
- Katip.Core: instance Show Environment
- Katip.Core: instance Show LocShow
- Katip.Core: instance Show LogStr
- Katip.Core: instance Show Namespace
- Katip.Core: instance Show Severity
- Katip.Core: instance Show ThreadIdText
- Katip.Core: instance Show Verbosity
- Katip.Core: instance Show a => Show (Item a)
- Katip.Core: instance ToJSON Environment
- Katip.Core: instance ToJSON LocJs
- Katip.Core: instance ToJSON Namespace
- Katip.Core: instance ToJSON ProcessIDJs
- Katip.Core: instance ToJSON Severity
- Katip.Core: instance ToJSON SimpleLogPayload
- Katip.Core: instance ToJSON ThreadIdText
- Katip.Core: instance ToJSON a => ToJSON (Item a)
- Katip.Core: instance ToObject ()
- Katip.Core: instance ToObject Object
- Katip.Core: instance ToObject SimpleLogPayload
- Katip.Core: liPush :: Scribe -> forall a. LogItem a => Item a -> IO ()
- Katip.Core: logEnvNs :: Lens' LogEnv Namespace
- Katip.Core: processIDText :: Prism' Text ProcessID
- Katip.Core: severityText :: Prism' Text Severity
- Katip.Core: unKatipT :: KatipT m a -> ReaderT LogEnv m a
- Katip.Core: unLogStr :: LogStr -> Builder
- Katip.Core: unNamespace :: Namespace -> [Text]
- Katip.Core: unSimpleLogPayload :: SimpleLogPayload -> [(Text, AnyLogPayload)]
- Katip.Monadic: instance (KatipContext m, Katip (EitherT e m)) => KatipContext (EitherT e m)
- Katip.Monadic: instance (KatipContext m, Katip (ExceptT s m)) => KatipContext (ExceptT s m)
- Katip.Monadic: instance (KatipContext m, Katip (IdentityT m)) => KatipContext (IdentityT m)
- Katip.Monadic: instance (KatipContext m, Katip (ListT m)) => KatipContext (ListT m)
- Katip.Monadic: instance (KatipContext m, Katip (MaybeT m)) => KatipContext (MaybeT m)
- Katip.Monadic: instance (KatipContext m, Katip (ReaderT r m)) => KatipContext (ReaderT r m)
- Katip.Monadic: instance (KatipContext m, Katip (ResourceT m)) => KatipContext (ResourceT m)
- Katip.Monadic: instance (KatipContext m, Katip (StateT s m)) => KatipContext (StateT s m)
- Katip.Monadic: instance (Monad m, KatipContext m) => KatipContext (KatipT m)
- Katip.Monadic: instance (Monoid w, KatipContext m, Katip (RWST r w s m)) => KatipContext (RWST r w s m)
- Katip.Monadic: instance (Monoid w, KatipContext m, Katip (WriterT w m)) => KatipContext (WriterT w m)
- Katip.Monadic: instance Alternative m => Alternative (KatipContextT m)
- Katip.Monadic: instance Applicative m => Applicative (KatipContextT m)
- Katip.Monadic: instance Functor m => Functor (KatipContextT m)
- Katip.Monadic: instance LogItem LogContexts
- Katip.Monadic: instance Monad m => Monad (KatipContextT m)
- Katip.Monadic: instance MonadBase b m => MonadBase b (KatipContextT m)
- Katip.Monadic: instance MonadBaseControl b m => MonadBaseControl b (KatipContextT m)
- Katip.Monadic: instance MonadCatch m => MonadCatch (KatipContextT m)
- Katip.Monadic: instance MonadError e m => MonadError e (KatipContextT m)
- Katip.Monadic: instance MonadFix m => MonadFix (KatipContextT m)
- Katip.Monadic: instance MonadIO m => Katip (KatipContextT m)
- Katip.Monadic: instance MonadIO m => KatipContext (KatipContextT m)
- Katip.Monadic: instance MonadIO m => MonadIO (KatipContextT m)
- Katip.Monadic: instance MonadMask m => MonadMask (KatipContextT m)
- Katip.Monadic: instance MonadPlus m => MonadPlus (KatipContextT m)
- Katip.Monadic: instance MonadReader r m => MonadReader r (KatipContextT m)
- Katip.Monadic: instance MonadState s m => MonadState s (KatipContextT m)
- Katip.Monadic: instance MonadThrow m => MonadThrow (KatipContextT m)
- Katip.Monadic: instance MonadTrans KatipContextT
- Katip.Monadic: instance MonadTransControl KatipContextT
- Katip.Monadic: instance MonadWriter w m => MonadWriter w (KatipContextT m)
- Katip.Monadic: instance Monoid LogContexts
- Katip.Monadic: instance ToJSON LogContexts
- Katip.Monadic: instance ToObject LogContexts
- Katip.Monadic: ltsContext :: KatipContextTState -> !LogContexts
- Katip.Monadic: ltsLogEnv :: KatipContextTState -> !LogEnv
- Katip.Monadic: ltsNamespace :: KatipContextTState -> !Namespace
- Katip.Monadic: unKatipContextT :: KatipContextT m a -> ReaderT KatipContextTState m a
- Katip.Scribes.Handle: renderPrim :: Primitive -> Builder
+ Katip: [_itemApp] :: Item a -> Namespace
+ Katip: [_itemEnv] :: Item a -> Environment
+ Katip: [_itemHost] :: Item a -> HostName
+ Katip: [_itemLoc] :: Item a -> Maybe Loc
+ Katip: [_itemMessage] :: Item a -> LogStr
+ Katip: [_itemNamespace] :: Item a -> Namespace
+ Katip: [_itemPayload] :: Item a -> a
+ Katip: [_itemProcess] :: Item a -> ProcessID
+ Katip: [_itemSeverity] :: Item a -> Severity
+ Katip: [_itemThread] :: Item a -> ThreadIdText
+ Katip: [_itemTime] :: Item a -> UTCTime
+ Katip: [_logEnvApp] :: LogEnv -> Namespace
+ Katip: [_logEnvEnv] :: LogEnv -> Environment
+ Katip: [_logEnvHost] :: LogEnv -> HostName
+ Katip: [_logEnvPid] :: LogEnv -> ProcessID
+ Katip: [_logEnvScribes] :: LogEnv -> Map Text Scribe
+ Katip: [_logEnvTimer] :: LogEnv -> IO UTCTime
+ Katip: [getEnvironment] :: Environment -> Text
+ Katip: [getThreadIdText] :: ThreadIdText -> Text
+ Katip: [liPush] :: Scribe -> forall a. LogItem a => Item a -> IO ()
+ Katip: [unKatipT] :: KatipT m a -> ReaderT LogEnv m a
+ Katip: [unLogStr] :: LogStr -> Builder
+ Katip: [unNamespace] :: Namespace -> [Text]
+ Katip: katipAddContext :: (LogItem i, Monad m) => i -> KatipContextT m a -> KatipContextT m a
+ Katip: katipAddNamespace :: (Monad m) => Namespace -> KatipContextT m a -> KatipContextT m a
+ Katip: logEnvApp :: Lens' LogEnv Namespace
+ Katip: textToSeverity :: Text -> Maybe Severity
+ Katip.Core: [_itemApp] :: Item a -> Namespace
+ Katip.Core: [_itemEnv] :: Item a -> Environment
+ Katip.Core: [_itemHost] :: Item a -> HostName
+ Katip.Core: [_itemLoc] :: Item a -> Maybe Loc
+ Katip.Core: [_itemMessage] :: Item a -> LogStr
+ Katip.Core: [_itemNamespace] :: Item a -> Namespace
+ Katip.Core: [_itemPayload] :: Item a -> a
+ Katip.Core: [_itemProcess] :: Item a -> ProcessID
+ Katip.Core: [_itemSeverity] :: Item a -> Severity
+ Katip.Core: [_itemThread] :: Item a -> ThreadIdText
+ Katip.Core: [_itemTime] :: Item a -> UTCTime
+ Katip.Core: [_logEnvApp] :: LogEnv -> Namespace
+ Katip.Core: [_logEnvEnv] :: LogEnv -> Environment
+ Katip.Core: [_logEnvHost] :: LogEnv -> HostName
+ Katip.Core: [_logEnvPid] :: LogEnv -> ProcessID
+ Katip.Core: [_logEnvScribes] :: LogEnv -> Map Text Scribe
+ Katip.Core: [_logEnvTimer] :: LogEnv -> IO UTCTime
+ Katip.Core: [getEnvironment] :: Environment -> Text
+ Katip.Core: [getLocJs] :: LocJs -> Loc
+ Katip.Core: [getProcessIDJs] :: ProcessIDJs -> ProcessID
+ Katip.Core: [getThreadIdText] :: ThreadIdText -> Text
+ Katip.Core: [liPush] :: Scribe -> forall a. LogItem a => Item a -> IO ()
+ Katip.Core: [unKatipT] :: KatipT m a -> ReaderT LogEnv m a
+ Katip.Core: [unLogStr] :: LogStr -> Builder
+ Katip.Core: [unNamespace] :: Namespace -> [Text]
+ Katip.Core: [unSimpleLogPayload] :: SimpleLogPayload -> [(Text, AnyLogPayload)]
+ Katip.Core: getLocTH :: ExpQ
+ Katip.Core: instance (Katip.Core.Katip m, GHC.Base.Monoid s) => Katip.Core.Katip (Control.Monad.Trans.Writer.Lazy.WriterT s m)
+ Katip.Core: instance Control.Monad.Base.MonadBase b m => Control.Monad.Base.MonadBase b (Katip.Core.KatipT m)
+ Katip.Core: instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Katip.Core.KatipT m)
+ Katip.Core: instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Katip.Core.KatipT m)
+ Katip.Core: instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Katip.Core.KatipT m)
+ Katip.Core: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Katip.Core.KatipT m)
+ Katip.Core: instance Control.Monad.IO.Class.MonadIO m => Katip.Core.Katip (Katip.Core.KatipT m)
+ Katip.Core: instance Control.Monad.Trans.Class.MonadTrans Katip.Core.KatipT
+ Katip.Core: instance Control.Monad.Trans.Control.MonadBaseControl b m => Control.Monad.Trans.Control.MonadBaseControl b (Katip.Core.KatipT m)
+ Katip.Core: instance Control.Monad.Trans.Control.MonadTransControl Katip.Core.KatipT
+ Katip.Core: instance Data.Aeson.Types.Class.FromJSON Katip.Core.Environment
+ Katip.Core: instance Data.Aeson.Types.Class.FromJSON Katip.Core.LocJs
+ Katip.Core: instance Data.Aeson.Types.Class.FromJSON Katip.Core.LogStr
+ Katip.Core: instance Data.Aeson.Types.Class.FromJSON Katip.Core.Namespace
+ Katip.Core: instance Data.Aeson.Types.Class.FromJSON Katip.Core.ProcessIDJs
+ Katip.Core: instance Data.Aeson.Types.Class.FromJSON Katip.Core.Severity
+ Katip.Core: instance Data.Aeson.Types.Class.FromJSON Katip.Core.ThreadIdText
+ Katip.Core: instance Data.Aeson.Types.Class.FromJSON a => Data.Aeson.Types.Class.FromJSON (Katip.Core.Item a)
+ Katip.Core: instance Data.Aeson.Types.Class.ToJSON Katip.Core.Environment
+ Katip.Core: instance Data.Aeson.Types.Class.ToJSON Katip.Core.LocJs
+ Katip.Core: instance Data.Aeson.Types.Class.ToJSON Katip.Core.Namespace
+ Katip.Core: instance Data.Aeson.Types.Class.ToJSON Katip.Core.ProcessIDJs
+ Katip.Core: instance Data.Aeson.Types.Class.ToJSON Katip.Core.Severity
+ Katip.Core: instance Data.Aeson.Types.Class.ToJSON Katip.Core.SimpleLogPayload
+ Katip.Core: instance Data.Aeson.Types.Class.ToJSON Katip.Core.ThreadIdText
+ Katip.Core: instance Data.Aeson.Types.Class.ToJSON a => Data.Aeson.Types.Class.ToJSON (Katip.Core.Item a)
+ Katip.Core: instance Data.String.IsString Katip.Core.Environment
+ Katip.Core: instance Data.String.IsString Katip.Core.LogStr
+ Katip.Core: instance Data.String.IsString Katip.Core.Namespace
+ Katip.Core: instance GHC.Base.Applicative m => GHC.Base.Applicative (Katip.Core.KatipT m)
+ Katip.Core: instance GHC.Base.Functor Katip.Core.Item
+ Katip.Core: instance GHC.Base.Functor m => GHC.Base.Functor (Katip.Core.KatipT m)
+ Katip.Core: instance GHC.Base.Monad m => GHC.Base.Monad (Katip.Core.KatipT m)
+ Katip.Core: instance GHC.Base.Monoid Katip.Core.LogStr
+ Katip.Core: instance GHC.Base.Monoid Katip.Core.Namespace
+ Katip.Core: instance GHC.Base.Monoid Katip.Core.PayloadSelection
+ Katip.Core: instance GHC.Base.Monoid Katip.Core.Scribe
+ Katip.Core: instance GHC.Base.Monoid Katip.Core.SimpleLogPayload
+ Katip.Core: instance GHC.Classes.Eq Katip.Core.Environment
+ Katip.Core: instance GHC.Classes.Eq Katip.Core.Namespace
+ Katip.Core: instance GHC.Classes.Eq Katip.Core.PayloadSelection
+ Katip.Core: instance GHC.Classes.Eq Katip.Core.Severity
+ Katip.Core: instance GHC.Classes.Eq Katip.Core.ThreadIdText
+ Katip.Core: instance GHC.Classes.Eq Katip.Core.Verbosity
+ Katip.Core: instance GHC.Classes.Ord Katip.Core.Environment
+ Katip.Core: instance GHC.Classes.Ord Katip.Core.Namespace
+ Katip.Core: instance GHC.Classes.Ord Katip.Core.Severity
+ Katip.Core: instance GHC.Classes.Ord Katip.Core.ThreadIdText
+ Katip.Core: instance GHC.Classes.Ord Katip.Core.Verbosity
+ Katip.Core: instance GHC.Enum.Bounded Katip.Core.Severity
+ Katip.Core: instance GHC.Enum.Enum Katip.Core.Severity
+ Katip.Core: instance GHC.Enum.Enum Katip.Core.Verbosity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_0Environment
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_0Item
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_0LogStr
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_0Namespace
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_0Severity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_0Verbosity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_1Severity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_1Verbosity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_2Severity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_2Verbosity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_3Severity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_3Verbosity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_4Severity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_5Severity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_6Severity
+ Katip.Core: instance GHC.Generics.Constructor Katip.Core.C1_7Severity
+ Katip.Core: instance GHC.Generics.Datatype Katip.Core.D1Environment
+ Katip.Core: instance GHC.Generics.Datatype Katip.Core.D1Item
+ Katip.Core: instance GHC.Generics.Datatype Katip.Core.D1LogStr
+ Katip.Core: instance GHC.Generics.Datatype Katip.Core.D1Namespace
+ Katip.Core: instance GHC.Generics.Datatype Katip.Core.D1Severity
+ Katip.Core: instance GHC.Generics.Datatype Katip.Core.D1Verbosity
+ Katip.Core: instance GHC.Generics.Generic (Katip.Core.Item a)
+ Katip.Core: instance GHC.Generics.Generic Katip.Core.Environment
+ Katip.Core: instance GHC.Generics.Generic Katip.Core.LogStr
+ Katip.Core: instance GHC.Generics.Generic Katip.Core.Namespace
+ Katip.Core: instance GHC.Generics.Generic Katip.Core.Severity
+ Katip.Core: instance GHC.Generics.Generic Katip.Core.Verbosity
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_0Environment
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_0Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_0LogStr
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_0Namespace
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_10Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_1Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_2Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_3Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_4Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_5Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_6Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_7Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_8Item
+ Katip.Core: instance GHC.Generics.Selector Katip.Core.S1_0_9Item
+ Katip.Core: instance GHC.Read.Read Katip.Core.Environment
+ Katip.Core: instance GHC.Read.Read Katip.Core.Namespace
+ Katip.Core: instance GHC.Read.Read Katip.Core.Severity
+ Katip.Core: instance GHC.Read.Read Katip.Core.Verbosity
+ Katip.Core: instance GHC.Show.Show Katip.Core.Environment
+ Katip.Core: instance GHC.Show.Show Katip.Core.LocShow
+ Katip.Core: instance GHC.Show.Show Katip.Core.LogStr
+ Katip.Core: instance GHC.Show.Show Katip.Core.Namespace
+ Katip.Core: instance GHC.Show.Show Katip.Core.PayloadSelection
+ Katip.Core: instance GHC.Show.Show Katip.Core.Severity
+ Katip.Core: instance GHC.Show.Show Katip.Core.ThreadIdText
+ Katip.Core: instance GHC.Show.Show Katip.Core.Verbosity
+ Katip.Core: instance GHC.Show.Show a => GHC.Show.Show (Katip.Core.Item a)
+ Katip.Core: instance Katip.Core.Katip m => Katip.Core.Katip (Control.Monad.Trans.Either.EitherT s m)
+ Katip.Core: instance Katip.Core.Katip m => Katip.Core.Katip (Control.Monad.Trans.Except.ExceptT s m)
+ Katip.Core: instance Katip.Core.Katip m => Katip.Core.Katip (Control.Monad.Trans.Maybe.MaybeT m)
+ Katip.Core: instance Katip.Core.Katip m => Katip.Core.Katip (Control.Monad.Trans.Reader.ReaderT s m)
+ Katip.Core: instance Katip.Core.Katip m => Katip.Core.Katip (Control.Monad.Trans.Resource.Internal.ResourceT m)
+ Katip.Core: instance Katip.Core.Katip m => Katip.Core.Katip (Control.Monad.Trans.State.Lazy.StateT s m)
+ Katip.Core: instance Katip.Core.LogItem ()
+ Katip.Core: instance Katip.Core.LogItem Katip.Core.SimpleLogPayload
+ Katip.Core: instance Katip.Core.ToObject ()
+ Katip.Core: instance Katip.Core.ToObject Data.Aeson.Types.Internal.Object
+ Katip.Core: instance Katip.Core.ToObject Katip.Core.SimpleLogPayload
+ Katip.Core: instance Language.Haskell.TH.Syntax.Lift Katip.Core.Namespace
+ Katip.Core: instance Language.Haskell.TH.Syntax.Lift Katip.Core.Severity
+ Katip.Core: instance Language.Haskell.TH.Syntax.Lift Katip.Core.Verbosity
+ Katip.Core: logEnvApp :: Lens' LogEnv Namespace
+ Katip.Core: logLoc :: (Applicative m, LogItem a, Katip m) => a -> Namespace -> Severity -> LogStr -> m ()
+ Katip.Core: processIDToText :: ProcessID -> Text
+ Katip.Core: readMay :: Read a => String -> Maybe a
+ Katip.Core: textToProcessID :: Text -> Maybe ProcessID
+ Katip.Core: textToSeverity :: Text -> Maybe Severity
+ Katip.Monadic: [ltsContext] :: KatipContextTState -> !LogContexts
+ Katip.Monadic: [ltsLogEnv] :: KatipContextTState -> !LogEnv
+ Katip.Monadic: [ltsNamespace] :: KatipContextTState -> !Namespace
+ Katip.Monadic: [unKatipContextT] :: KatipContextT m a -> ReaderT KatipContextTState m a
+ Katip.Monadic: instance (GHC.Base.Monad m, Katip.Monadic.KatipContext m) => Katip.Monadic.KatipContext (Katip.Core.KatipT m)
+ Katip.Monadic: instance (GHC.Base.Monoid w, Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.RWS.Lazy.RWST r w s m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.RWS.Lazy.RWST r w s m)
+ Katip.Monadic: instance (GHC.Base.Monoid w, Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.RWS.Strict.RWST r w s m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.RWS.Strict.RWST r w s m)
+ Katip.Monadic: instance (GHC.Base.Monoid w, Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.Writer.Lazy.WriterT w m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.Writer.Lazy.WriterT w m)
+ Katip.Monadic: instance (GHC.Base.Monoid w, Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.Writer.Strict.WriterT w m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.Writer.Strict.WriterT w m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.Either.EitherT e m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.Either.EitherT e m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.Except.ExceptT s m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.Except.ExceptT s m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.Identity.IdentityT m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.Identity.IdentityT m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.List.ListT m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.List.ListT m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.Maybe.MaybeT m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.Maybe.MaybeT m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.Reader.ReaderT r m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.Reader.ReaderT r m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.Resource.Internal.ResourceT m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.Resource.Internal.ResourceT m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.State.Lazy.StateT s m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.State.Lazy.StateT s m)
+ Katip.Monadic: instance (Katip.Monadic.KatipContext m, Katip.Core.Katip (Control.Monad.Trans.State.Strict.StateT s m)) => Katip.Monadic.KatipContext (Control.Monad.Trans.State.Strict.StateT s m)
+ Katip.Monadic: instance Control.Monad.Base.MonadBase b m => Control.Monad.Base.MonadBase b (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.Error.Class.MonadError e m => Control.Monad.Error.Class.MonadError e (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.IO.Class.MonadIO m => Katip.Core.Katip (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.IO.Class.MonadIO m => Katip.Monadic.KatipContext (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.Reader.Class.MonadReader r m => Control.Monad.Reader.Class.MonadReader r (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.State.Class.MonadState s m => Control.Monad.State.Class.MonadState s (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.Trans.Class.MonadTrans Katip.Monadic.KatipContextT
+ Katip.Monadic: instance Control.Monad.Trans.Control.MonadBaseControl b m => Control.Monad.Trans.Control.MonadBaseControl b (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Control.Monad.Trans.Control.MonadTransControl Katip.Monadic.KatipContextT
+ Katip.Monadic: instance Control.Monad.Writer.Class.MonadWriter w m => Control.Monad.Writer.Class.MonadWriter w (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance Data.Aeson.Types.Class.ToJSON Katip.Monadic.LogContexts
+ Katip.Monadic: instance GHC.Base.Alternative m => GHC.Base.Alternative (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance GHC.Base.Applicative m => GHC.Base.Applicative (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance GHC.Base.Functor m => GHC.Base.Functor (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance GHC.Base.Monad m => GHC.Base.Monad (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Katip.Monadic.KatipContextT m)
+ Katip.Monadic: instance GHC.Base.Monoid Katip.Monadic.LogContexts
+ Katip.Monadic: instance Katip.Core.LogItem Katip.Monadic.LogContexts
+ Katip.Monadic: instance Katip.Core.ToObject Katip.Monadic.LogContexts
+ Katip.Monadic: katipAddContext :: (LogItem i, Monad m) => i -> KatipContextT m a -> KatipContextT m a
+ Katip.Monadic: katipAddNamespace :: (Monad m) => Namespace -> KatipContextT m a -> KatipContextT m a
+ Katip.Monadic: logLocM :: (Applicative m, KatipContext m, Katip m) => Severity -> LogStr -> m ()
- Katip: itemApp :: Lens' (Item a_akrY) Namespace
+ Katip: itemApp :: Lens' (Item a_agYl) Namespace
- Katip: itemEnv :: Lens' (Item a_akrY) Environment
+ Katip: itemEnv :: Lens' (Item a_agYl) Environment
- Katip: itemHost :: Lens' (Item a_akrY) HostName
+ Katip: itemHost :: Lens' (Item a_agYl) HostName
- Katip: itemLoc :: Lens' (Item a_akrY) (Maybe Loc)
+ Katip: itemLoc :: Lens' (Item a_agYl) (Maybe Loc)
- Katip: itemMessage :: Lens' (Item a_akrY) LogStr
+ Katip: itemMessage :: Lens' (Item a_agYl) LogStr
- Katip: itemNamespace :: Lens' (Item a_akrY) Namespace
+ Katip: itemNamespace :: Lens' (Item a_agYl) Namespace
- Katip: itemPayload :: Lens (Item a_akrY) (Item a_aoxY) a_akrY a_aoxY
+ Katip: itemPayload :: Lens (Item a_agYl) (Item a_an5P) a_agYl a_an5P
- Katip: itemProcess :: Lens' (Item a_akrY) ProcessID
+ Katip: itemProcess :: Lens' (Item a_agYl) ProcessID
- Katip: itemSeverity :: Lens' (Item a_akrY) Severity
+ Katip: itemSeverity :: Lens' (Item a_agYl) Severity
- Katip: itemThread :: Lens' (Item a_akrY) ThreadIdText
+ Katip: itemThread :: Lens' (Item a_agYl) ThreadIdText
- Katip: itemTime :: Lens' (Item a_akrY) UTCTime
+ Katip: itemTime :: Lens' (Item a_agYl) UTCTime
- Katip: liftPayload :: LogItem a => a -> LogContexts
+ Katip: liftPayload :: (LogItem a) => a -> LogContexts
- Katip: runKatipContextT :: LogItem c => LogEnv -> c -> Namespace -> KatipContextT m a -> m a
+ Katip: runKatipContextT :: (LogItem c) => LogEnv -> c -> Namespace -> KatipContextT m a -> m a
- Katip.Core: getLoc :: Q Exp
+ Katip.Core: getLoc :: (?loc :: CallStack) => Maybe Loc
- Katip.Core: itemApp :: Lens' (Item a_akrY) Namespace
+ Katip.Core: itemApp :: Lens' (Item a_agYl) Namespace
- Katip.Core: itemEnv :: Lens' (Item a_akrY) Environment
+ Katip.Core: itemEnv :: Lens' (Item a_agYl) Environment
- Katip.Core: itemHost :: Lens' (Item a_akrY) HostName
+ Katip.Core: itemHost :: Lens' (Item a_agYl) HostName
- Katip.Core: itemLoc :: Lens' (Item a_akrY) (Maybe Loc)
+ Katip.Core: itemLoc :: Lens' (Item a_agYl) (Maybe Loc)
- Katip.Core: itemMessage :: Lens' (Item a_akrY) LogStr
+ Katip.Core: itemMessage :: Lens' (Item a_agYl) LogStr
- Katip.Core: itemNamespace :: Lens' (Item a_akrY) Namespace
+ Katip.Core: itemNamespace :: Lens' (Item a_agYl) Namespace
- Katip.Core: itemPayload :: Lens (Item a_akrY) (Item a_aoxY) a_akrY a_aoxY
+ Katip.Core: itemPayload :: Lens (Item a_agYl) (Item a_an5P) a_agYl a_an5P
- Katip.Core: itemProcess :: Lens' (Item a_akrY) ProcessID
+ Katip.Core: itemProcess :: Lens' (Item a_agYl) ProcessID
- Katip.Core: itemSeverity :: Lens' (Item a_akrY) Severity
+ Katip.Core: itemSeverity :: Lens' (Item a_agYl) Severity
- Katip.Core: itemThread :: Lens' (Item a_akrY) ThreadIdText
+ Katip.Core: itemThread :: Lens' (Item a_agYl) ThreadIdText
- Katip.Core: itemTime :: Lens' (Item a_akrY) UTCTime
+ Katip.Core: itemTime :: Lens' (Item a_agYl) UTCTime
- Katip.Monadic: liftPayload :: LogItem a => a -> LogContexts
+ Katip.Monadic: liftPayload :: (LogItem a) => a -> LogContexts
- Katip.Monadic: runKatipContextT :: LogItem c => LogEnv -> c -> Namespace -> KatipContextT m a -> m a
+ Katip.Monadic: runKatipContextT :: (LogItem c) => LogEnv -> c -> Namespace -> KatipContextT m a -> m a
Files
- README.md +6/−3
- changelog.md +17/−0
- examples/example.hs +3/−2
- examples/example_lens.hs +3/−2
- katip.cabal +14/−6
- src/Katip.hs +108/−13
- src/Katip/Core.hs +109/−37
- src/Katip/Monadic.hs +67/−7
- src/Katip/Scribes/Handle.hs +13/−13
- test/Katip/Tests.hs +58/−1
- test/Katip/Tests/Scribes/Handle.hs +8/−4
README.md view
@@ -2,7 +2,7 @@ Katip is a structured logging framework for Haskell. -+ Kâtip (pronounced kah-tip) is the Turkish word for scribe. @@ -69,8 +69,11 @@ ## Examples-Be sure to look in the [examples](./examples) directory for some examples of how-to integrate Katip into your own stack.++Be sure to look in the+[examples](https://github.com/Soostone/katip/blob/master/katip/examples)+directory for some examples of how to integrate Katip into your own+stack. ## Contributors
changelog.md view
@@ -1,3 +1,20 @@+0.2.0.0+=======++* Add GHC implicit callstack support, add logLoc.+* Drop lens in favor of type-compatible, lighter microlens.+* Renamed `logEnvNs` to clearer `logEnvApp`+* Added `katipAddNamespace` and `katipAddContext`+* Fixed nested objects not rendering in Handle scribe.+* LogContexts Monoid instance is now right-biased rather than left+ biased. This better fits the use case. For instance `ctx1 <> ctx2`+ will prefer keys in `ctx2` if there are conflicts. This makes the+ most sense because functions like `katipAddContext` will `mappend`+ on the right side.+* LogContext internally uses a `Seq` instead of a list for better+ complexity on context add.+* Improved documentation.+ 0.1.1.0 ==============
examples/example.hs view
@@ -9,6 +9,7 @@ -------------------------------------------------------------------------------+import qualified Control.Applicative as A import Control.Monad.Reader import Data.Aeson import Data.Monoid as M@@ -22,7 +23,7 @@ -- lens_example for a slightly cleaner and more general pattern. main :: IO () main = do- le <- initLogEnv "main" "production"+ le <- initLogEnv "MyApp" "production" -- We'll set up a scribe that logs to stdout and will only log item -- fields permitted for Verbosity 2 and will throw out Debug -- messages entirely. Note that katip provides facilities like@@ -77,7 +78,7 @@ ------------------------------------------------------------------------------- newtype MyStack m a = MyStack { unStack :: ReaderT MyState m a- } deriving (MonadReader MyState, Functor, Applicative, Monad, MonadIO)+ } deriving (MonadReader MyState, Functor, A.Applicative, Monad, MonadIO) instance (MonadIO m) => Katip (MyStack m) where
examples/example_lens.hs view
@@ -9,6 +9,7 @@ -------------------------------------------------------------------------------+import Control.Applicative as A import Control.Lens hiding ((.=)) import Control.Monad.Reader import Data.Aeson@@ -38,7 +39,7 @@ -- lens_example for a slightly cleaner and more general pattern. main :: IO () main = do- le <- initLogEnv "main" "production"+ le <- initLogEnv "MyApp" "production" -- We'll set up a scribe that logs to stdout and will only log item -- fields permitted for Verbosity 2 and will throw out Debug -- messages entirely. Note that katip provides facilities like@@ -85,7 +86,7 @@ ------------------------------------------------------------------------------- newtype MyStack m a = MyStack { unStack :: ReaderT MyState m a- } deriving (MonadReader MyState, Functor, Applicative, Monad, MonadIO)+ } deriving (MonadReader MyState, Functor, A.Applicative, Monad, MonadIO) instance (MonadIO m) => Katip (MyStack m) where
katip.cabal view
@@ -1,5 +1,5 @@ name: katip-version: 0.1.1.0+version: 0.2.0.0 synopsis: A structured logging framework. description: Katip is a structured logging framework. See README.md for more details.@@ -10,6 +10,8 @@ maintainer: ozgun.ataman@soostone.com copyright: Soostone Inc, 2015-2016 category: Data, Text, Logging+homepage: https://github.com/Soostone/katip+bug-reports: https://github.com/Soostone/katip/issues build-type: Simple cabal-version: >=1.10 extra-source-files:@@ -21,7 +23,12 @@ test/Main.hs test/Katip/Tests.hs test/Katip/Tests/Scribes/Handle.hs+tested-with: GHC == 7.8.4, GHC== 7.10.3 +source-repository head+ type: git+ location: https://github.com/Soostone/katip.git+ flag lib-Werror default: False manual: True@@ -51,22 +58,22 @@ , either >= 4 && < 4.5 , exceptions >= 0.5 && < 0.9 , hostname >=1.0 && <1.1- , lens >= 4.4 && <4.14- , lens-aeson < 1.1 , old-locale >= 1.0 && < 1.1 , string-conv >= 0.1 && < 0.2 , template-haskell >= 2.8 && < 2.11 , text >= 0.11 && <1.3 , time >= 1 && < 1.6 , time-locale-compat >= 0.1.0.1 && < 0.2- , transformers >= 0.3 && < 0.5+ , transformers >= 0.3 && < 0.6 , transformers-compat , unix >= 2.5 && < 2.8 , unordered-containers >= 0.2 && < 0.3 , monad-control >= 1.0 && < 1.1- , mtl >= 2.2 && < 2.3- , transformers-base >= 0.4.1 && < 0.5+ , mtl >= 2.0 && < 2.3+ , transformers-base >= 0.3 && < 0.5 , resourcet >= 1.1 && < 1.2+ , microlens >= 0.2.0.0 && < 0.5+ , microlens-th >= 0.1.0.0 && < 0.5 hs-source-dirs: src default-language: Haskell2010@@ -92,6 +99,7 @@ , temporary , directory , regex-tdfa-rc+ , unordered-containers benchmark bench
src/Katip.hs view
@@ -26,17 +26,22 @@ ( -- * Framework Types-- Katip (..)- , Namespace (..)+ Namespace (..) , Environment (..) , Severity (..) , renderSeverity- , severityText+ , textToSeverity , Verbosity (..) , ToObject (..) , LogItem (..) , Item(..)+ , ThreadIdText(..)+ , PayloadSelection (..)+ , Scribe (..)+ , LogEnv (..)+ , SimpleLogPayload, sl++ -- ** @lens@-compatible Lenses , itemApp , itemEnv , itemSeverity@@ -48,20 +53,12 @@ , itemTime , itemNamespace , itemLoc- , ThreadIdText(..)- , PayloadSelection (..)- , Scribe (..)- , LogEnv (..) , logEnvHost , logEnvPid- , logEnvNs+ , logEnvApp , logEnvEnv , logEnvTimer , logEnvScribes- , KatipContext(..)- , AnyLogContext- , LogContexts, liftPayload- , SimpleLogPayload, sl -- * A Built-in Monad For Logging , KatipT (..)@@ -77,15 +74,23 @@ , LogStr (..) , logStr, ls, showLS + -- ** 'Katip' LoggingFunctions+ -- $katiplogging+ , Katip (..) , logF , logMsg , logT , logItem , logException+ -- ** 'KatipContext' Logging Functions+ -- $katipcontextlogging+ , KatipContext (..) , logFM , logTM , logItemM , logExceptionM+ , AnyLogContext+ , LogContexts, liftPayload -- * Included Scribes , mkHandleScribe@@ -99,6 +104,8 @@ -- * KatipContextT - Utility transformer that provides Katip and KatipContext instances , KatipContextT , runKatipContextT+ , katipAddNamespace+ , katipAddContext ) where -------------------------------------------------------------------------------@@ -106,3 +113,91 @@ import Katip.Monadic import Katip.Scribes.Handle -------------------------------------------------------------------------------+++{- $katiplogging++ These logging functions use the basic 'Katip' constraint and thus+will require varying degrees of explicit detail such as 'Namespace'+and individual log items to be passed in. These can be described as+the primitives of Katip logging. If you find yourself making multiple+log statements within a logical logging context for your app, you may+want to look into the 'KatipContext' family of logging functions like+'logFM' and 'logTM'. 'KatipContext' in most applications should be+considered the default. Here's an example of the pain point:++@+doDatabaseThings = do+ connId <- getConnectionId+ logF (ConnectionIDContext connId) "database" InfoS "Doing database stuff"+ \-\- ...+ logF (ConnectionIDContext connId) "database" InfoS "Wow, passing in the same context is getting tedious"+@++Another pain point to look out for is nesting actions that log in+eachother. Let's say you were writing a web app. You want to capture+some detail such as the user's ID in the logs, but you also want that+info to show up in doDatabaseThings' logs so you can associate those+two pieces of information:+++@+webRequestHandler = do+ uid <- getUserId+ logF (UserIDContext uid) "web" InfoS "Starting web request"+ doDatabaseThings+@++In the above example, doDatabaseThings would overwrite that+UderIDContext with its own context and namespace. Sometimes this is+what you want and that's why 'logF' and other functions which only+require 'Katip' exist. If you are interested in combining log+contexts and namespaces, see 'KatipContext'.+-}+++{- $katipcontextlogging++ These logging functions use the 'KatipContext' constraint which is a+superclass of 'Katip' that also has a mechanism for keeping track of+the current context and namespace. This means a few things:++1. Functions that use 'KatipContext' like 'logFM' and 'logTM' do not+require you to pass in 'LogItem's or 'Namespaces', they pull them from+the monadic environment.++2. It becomes easy to add functions which add namespaces and/or+contexts to the current stack of them. You can (and should) make that+action scoped to a monadic action so that when it finishes, the+previous context and namespace will be automatically restored.+++'KatipContextT' provides a simple, 'ReaderT'-based implementation of+the 'KatipContext' typeclass, and provides 'katipAddContext' and+'katipAddNamespace' functions to append to the context for the+duration of a block:+++@+main = do+ le <- initLogEnv "MyApp" "production"+ \-\- set up scribes here+ runKatipContext le () "main" $ do+ katipAddNamespace "nextlevel" $ do+ $(logTM) InfoS "Logs here will have namespace MyApp.main.nextlevel"++ katipAddContext TrivialContext $ do+ $(logTM) InfoS "Logs here will have context from TrivialContext"++ katipAddContext AnotherContext $ do+ $(logTM) InfoS "Logs here will have context from TrivialContext *merged with* context from AnotherContext!"++ $(logTM) InfoS "Log context restored to () and namespace to MyApp.main"+@++'katipAddNamespace' and 'katipAddContext' are one-liners, implemented+in terms of 'local' from 'MonadReader'. If you have a custom monad+transformer stack and want to add your own version of these, check out+<https://github.com/Soostone/katip/tree/master/katip/examples these+examples>.+-}
src/Katip/Core.hs view
@@ -1,9 +1,11 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ImplicitParams #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}@@ -11,13 +13,14 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}+-- | This module is not meant to be imported directly and may contain+-- internal mechanisms that will change without notice. module Katip.Core where ------------------------------------------------------------------------------- import Control.Applicative as A import Control.AutoUpdate import Control.Concurrent-import Control.Lens import Control.Monad.Base import Control.Monad.Catch import Control.Monad.IO.Class@@ -45,13 +48,26 @@ import qualified Data.Text.Lazy.Builder as B import Data.Time import GHC.Generics hiding (to)+#if MIN_VERSION_base(4, 8, 0)+import GHC.SrcLoc+import GHC.Stack+#endif import Language.Haskell.TH import qualified Language.Haskell.TH.Syntax as TH+import Lens.Micro+import Lens.Micro.TH import Network.HostName import System.Posix ------------------------------------------------------------------------------- +readMay :: Read a => String -> Maybe a+readMay s = case [x | (x,t) <- reads s, ("","") <- lex t] of+ [x] -> Just x+ [] -> Nothing -- no parse+ _ -> Nothing -- Ambiguous parse++ ------------------------------------------------------------------------------- -- | Represents a heirarchy of namespaces going from general to -- specific. For instance: ["processname", "subsystem"]. Note that@@ -116,27 +132,25 @@ --------------------------------------------------------------------------------severityText :: Prism' Text Severity-severityText = prism renderSeverity toSev- where- toSev "Debug" = Right DebugS- toSev "Info" = Right InfoS- toSev "Notice" = Right NoticeS- toSev "Warning" = Right WarningS- toSev "Error" = Right ErrorS- toSev "Critical" = Right CriticalS- toSev "Alert" = Right AlertS- toSev "Emergency" = Right EmergencyS- toSev x = Left x+textToSeverity :: Text -> Maybe Severity+textToSeverity "Debug" = Just DebugS+textToSeverity "Info" = Just InfoS+textToSeverity "Notice" = Just NoticeS+textToSeverity "Warning" = Just WarningS+textToSeverity "Error" = Just ErrorS+textToSeverity "Critical" = Just CriticalS+textToSeverity "Alert" = Just AlertS+textToSeverity "Emergency" = Just EmergencyS+textToSeverity _ = Nothing -instance ToJSON Severity where- toJSON s = A.String (s ^. re severityText) +instance ToJSON Severity where+ toJSON s = A.String (renderSeverity s) instance FromJSON Severity where parseJSON = A.withText "Severity" parseSeverity where- parseSeverity t = case t ^? severityText of+ parseSeverity t = case textToSeverity t of Just x -> return x Nothing -> fail $ "Invalid Severity " ++ toS t @@ -289,28 +303,27 @@ <*> (fmap getLocJs <$> o A..: "loc") -processIDText :: Prism' Text ProcessID-processIDText = prism fromProcessID toProcessID- where- fromProcessID = toS . show- toProcessID t = case toS t ^? _Show of- Just i -> Right i- Nothing -> Left t+processIDToText :: ProcessID -> Text+processIDToText = toS . show +textToProcessID :: Text -> Maybe ProcessID+textToProcessID = readMay . toS++ newtype ProcessIDJs = ProcessIDJs { getProcessIDJs :: ProcessID } instance ToJSON ProcessIDJs where- toJSON (ProcessIDJs p) = A.String (p ^. re processIDText)+ toJSON (ProcessIDJs p) = A.String (processIDToText p) instance FromJSON ProcessIDJs where parseJSON = A.withText "ProcessID" parseProcessID where- parseProcessID t = case t ^? processIDText of+ parseProcessID t = case textToProcessID t of Just p -> return $ ProcessIDJs p Nothing -> fail $ "Invalid ProcessIDJs " ++ toS t @@ -320,6 +333,7 @@ data PayloadSelection = AllKeys | SomeKeys [Text]+ deriving (Show, Eq) instance Monoid PayloadSelection where mempty = SomeKeys []@@ -475,12 +489,18 @@ data LogEnv = LogEnv { _logEnvHost :: HostName , _logEnvPid :: ProcessID- , _logEnvNs :: Namespace+ , _logEnvApp :: Namespace+ -- ^ Name of application. This will typically never change. This+ -- field gets prepended to the namespace of your individual log+ -- messages. For example, if your app is MyApp and you write a log+ -- using "logItem" and the namespace "WebServer", the final+ -- namespace will be "MyApp.WebServer" , _logEnvEnv :: Environment , _logEnvTimer :: IO UTCTime -- ^ Action to fetch the timestamp. You can use something like -- 'AutoUpdate' for high volume logs but note that this may cause- -- some output forms to display logs out of order.+ -- some output forms to display logs out of order. Alternatively,+ -- you could just use 'getCurrentTime'. , _logEnvScribes :: M.Map Text Scribe } makeLenses ''LogEnv@@ -515,7 +535,7 @@ -> Scribe -> LogEnv -> LogEnv-registerScribe nm h = logEnvScribes . at nm .~ Just h+registerScribe nm h = logEnvScribes %~ M.insert nm h -------------------------------------------------------------------------------@@ -526,7 +546,7 @@ -- ^ Name of the scribe -> LogEnv -> LogEnv-unregisterScribe nm = logEnvScribes . at nm .~ Nothing+unregisterScribe nm = logEnvScribes %~ M.delete nm -------------------------------------------------------------------------------@@ -539,8 +559,16 @@ ---------------------------------------------------------------------------------- | Monads where katip logging actions can be performed-class MonadIO m => Katip m where+-- | Monads where katip logging actions can be performed. Katip is the+-- most basic logging monad. You will typically use this directly if+-- you either don't want to use namespaces/contexts heavily or if you+-- want to pass in specific contexts and/or namespaces at each log site.+--+-- For something more powerful, look at the docs for 'KatipContext',+-- which keeps a namespace and merged context. You can write simple+-- functions that add additional namespacing and merges additional+-- context on the fly.+class MonadIO m => Katip m where getLogEnv :: m LogEnv @@ -615,7 +643,7 @@ LogEnv{..} <- getLogEnv liftIO $ do item <- Item- <$> pure _logEnvNs+ <$> pure _logEnvApp <*> pure _logEnvEnv <*> pure sev <*> (mkThreadIdText <$> myThreadId)@@ -624,7 +652,7 @@ <*> pure a <*> pure msg <*> _logEnvTimer- <*> pure (_logEnvNs <> ns)+ <*> pure (_logEnvApp <> ns) <*> pure loc FT.forM_ (M.elems _logEnvScribes) $ \ (Scribe h) -> h item @@ -712,17 +740,61 @@ ------------------------------------------------------------------------------- -- | For use when you want to include location in your logs. This will--- fill the 'Maybe Loc' gap in 'logF' of this module.-getLoc :: Q Exp-getLoc = [| $(location >>= liftLoc) |]+-- fill the 'Maybe Loc' gap in 'logF' of this module, and relies on implicit+-- callstacks when available (GHC > 7.8).+#if MIN_VERSION_base(4, 8, 0)+getLoc :: (?loc :: CallStack) => Maybe Loc+getLoc = case getCallStack ?loc of+ [] -> Nothing+ xs -> Just . toLoc . last $ xs+ where+ toLoc :: (String, SrcLoc) -> Loc+ toLoc (_, l) = Loc {+ loc_filename = srcLocFile l+ , loc_package = srcLocPackage l+ , loc_module = srcLocModule l+ , loc_start = (srcLocStartLine l, srcLocStartCol l)+ , loc_end = (srcLocEndLine l, srcLocEndCol l)+ }+#else+getLoc :: Maybe Loc+getLoc = Nothing+#endif -------------------------------------------------------------------------------+-- Like `getLoc`, but uses template-haskell and works with older versions of+-- the compiler (GHC 7.8 or older).+getLocTH :: ExpQ+getLocTH = [| $(location >>= liftLoc) |]+++------------------------------------------------------------------------------- -- | 'Loc'-tagged logging when using template-haskell. -- -- @$(logT) obj mempty InfoS "Hello world"@ logT :: ExpQ-logT = [| \ a ns sev msg -> logItem a ns (Just $(getLoc)) sev msg |]+logT = [| \ a ns sev msg -> logItem a ns (Just $(getLocTH)) sev msg |]+++-------------------------------------------------------------------------------+-- | 'Loc'-tagged logging using implicit-callstacks when available.+--+-- This function does not require template-haskell as it+-- automatically uses <https://hackage.haskell.org/package/base-4.8.2.0/docs/GHC-Stack.html#v:getCallStack implicit-callstacks>+-- when the code is compiled using GHC > 7.8. Using an older version of the+-- compiler will result in the emission of a log line without any location information,+-- so be aware of it. Users using GHC <= 7.8 may want to use the template-haskell function+-- `logT` for maximum compatibility.+--+-- @logLoc obj mempty InfoS "Hello world"@+logLoc :: (Applicative m, LogItem a, Katip m)+ => a+ -> Namespace+ -> Severity+ -> LogStr+ -> m ()+logLoc a ns = logItem a ns getLoc -- taken from the file-location package
src/Katip/Monadic.hs view
@@ -16,6 +16,7 @@ -- * Monadic variants of logging functions from "Katip.Core" logFM , logTM+ , logLocM , logItemM , logExceptionM @@ -28,6 +29,8 @@ -- * KatipContextT - Utility transformer that provides Katip and KatipContext instances , KatipContextT(..) , runKatipContextT+ , katipAddNamespace+ , katipAddContext , KatipContextTState(..) ) where @@ -53,8 +56,10 @@ import qualified Control.Monad.Trans.Writer.Strict as Strict (WriterT) import Control.Monad.Writer import Data.Aeson+import qualified Data.Foldable as FT import qualified Data.HashMap.Strict as HM import Data.Monoid as M+import Data.Sequence as Seq import Data.Text (Text) import Language.Haskell.TH -------------------------------------------------------------------------------@@ -72,17 +77,29 @@ -- 'LogContext' instance for combining multiple payload policies. This -- is critical for log contexts deep down in a stack to be able to -- inject their own context without worrying about other context that--- has already been set.-newtype LogContexts = LogContexts [AnyLogContext] deriving (Monoid)+-- has already been set. Also note that contexts are treated as a+-- sequence and '<>' will be appended to the right hand side of the+-- sequence. If there are conflicting keys in the contexts, the /right+-- side will take precedence/, which is counter to how monoid works+-- for 'Map' and 'HashMap', so bear that in mind. The reasoning is+-- that if the user is /sequentially/ adding contexts to the right+-- side of the sequence, on conflict the intent is to overwrite with+-- the newer value (i.e. the rightmost value).+--+-- Additional note: you should not mappend LogContexts in any sort of+-- infinite loop, as it retains all data, so that would be a memory+-- leak.+newtype LogContexts = LogContexts (Seq AnyLogContext) deriving (Monoid) instance ToJSON LogContexts where toJSON (LogContexts cs) =- Object $ mconcat $ map (\(AnyLogContext v) -> toObject v) cs+ -- flip mappend to get right-biased merge+ Object $ FT.foldr (flip mappend) mempty $ fmap (\(AnyLogContext v) -> toObject v) cs instance ToObject LogContexts instance LogItem LogContexts where- payloadKeys verb (LogContexts vs) = mconcat $ map payloadKeys' vs+ payloadKeys verb (LogContexts vs) = FT.foldr (flip mappend) mempty $ fmap payloadKeys' vs where -- To ensure AllKeys doesn't leak keys from other values when -- combined, we resolve AllKeys to its equivalent SomeKeys@@ -96,7 +113,7 @@ -- | Lift a log context into the generic wrapper so that it can -- combine with the existing log context. liftPayload :: (LogItem a) => a -> LogContexts-liftPayload = LogContexts . (:[]) . AnyLogContext+liftPayload = LogContexts . Seq.singleton . AnyLogContext -------------------------------------------------------------------------------@@ -171,12 +188,33 @@ -- | 'Loc'-tagged logging when using template-haskell. Automatically -- supplies payload and namespace. ----- @$(logt) InfoS "Hello world"@+-- @$(logTM) InfoS "Hello world"@ logTM :: ExpQ-logTM = [| logItemM (Just $(getLoc)) |]+logTM = [| logItemM (Just $(getLocTH)) |] -------------------------------------------------------------------------------+-- | 'Loc'-tagged logging when using template-haskell. Automatically+-- supplies payload and namespace.+--+-- Same consideration as `logLoc` applies.+--+-- This function does not require template-haskell as it+-- automatically uses <https://hackage.haskell.org/package/base-4.8.2.0/docs/GHC-Stack.html#v:getCallStack implicit-callstacks>+-- when the code is compiled using GHC > 7.8. Using an older version of the+-- compiler will result in the emission of a log line without any location information,+-- so be aware of it. Users using GHC <= 7.8 may want to use the template-haskell function+-- `logTM` for maximum compatibility.+--+-- @logLocM InfoS "Hello world"@+logLocM :: (Applicative m, KatipContext m, Katip m)+ => Severity+ -> LogStr+ -> m ()+logLocM = logItemM getLoc+++------------------------------------------------------------------------------- -- | Perform an action while logging any exceptions that may occur. -- Inspired by 'onException`. --@@ -270,3 +308,25 @@ runKatipContextT le ctx ns = flip runReaderT lts . unKatipContextT where lts = KatipContextTState le (liftPayload ctx) ns+++-------------------------------------------------------------------------------+katipAddNamespace+ :: (Monad m)+ => Namespace+ -> KatipContextT m a+ -> KatipContextT m a+katipAddNamespace ns (KatipContextT f) =+ KatipContextT (local (\r -> r { ltsNamespace = (ltsNamespace r) <> ns}) f)+++-------------------------------------------------------------------------------+katipAddContext+ :: ( LogItem i+ , Monad m+ )+ => i+ -> KatipContextT m a+ -> KatipContextT m a+katipAddContext i (KatipContextT f) =+ KatipContextT (local (\r -> r { ltsContext = (ltsContext r) <> liftPayload i}) f)
src/Katip/Scribes/Handle.hs view
@@ -3,11 +3,12 @@ module Katip.Scribes.Handle where --------------------------------------------------------------------------------import Control.Lens+import Control.Applicative as A import Control.Monad-import Data.Aeson.Lens+import Data.Aeson import qualified Data.HashMap.Strict as HM import Data.Monoid+import Data.Text (Text) import Data.Text.Lazy.Builder import Data.Text.Lazy.IO as T import Data.Time@@ -26,18 +27,17 @@ ------------------------------------------------------------------------------- getKeys :: LogItem s => Verbosity -> s -> [Builder]-getKeys verb a = payloadObject verb a ^..- to HM.toList . traverse . to rendPair+getKeys verb a = concat (renderPair A.<$> HM.toList (payloadObject verb a)) where- rendPair (k,v) = fromText k <> fromText ":" <> (v ^. _Primitive . to renderPrim)-----------------------------------------------------------------------------------renderPrim :: Primitive -> Builder-renderPrim (StringPrim t) = fromText t-renderPrim (NumberPrim s) = fromString (show s)-renderPrim (BoolPrim b) = fromString (show b)-renderPrim NullPrim = fromText "null"+ renderPair :: (Text, Value) -> [Builder]+ renderPair (k,v) =+ case v of+ Object o -> concat [renderPair (k <> "." <> k', v') | (k', v') <- HM.toList o]+ String t -> [fromText (k <> ":" <> t)]+ Number n -> [fromText (k <> ":") <> fromString (show n)]+ Bool b -> [fromText (k <> ":") <> fromString (show b)]+ Null -> [fromText (k <> ":null")]+ _ -> mempty -- Can't think of a sensible way to handle arrays -------------------------------------------------------------------------------
test/Katip/Tests.hs view
@@ -1,4 +1,7 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# OPTIONS_GHC -fno-warn-orphans #-}@@ -10,6 +13,9 @@ ------------------------------------------------------------------------------- import Control.Applicative import Data.Aeson+import qualified Data.HashMap.Strict as HM+import Data.Monoid+import Data.Text (Text) import qualified Data.Text.Lazy.Builder as B import Data.Time import Data.Time.Clock.POSIX@@ -17,9 +23,11 @@ import System.Posix.Types import Test.QuickCheck.Instances () import Test.Tasty+import Test.Tasty.HUnit import Test.Tasty.QuickCheck ------------------------------------------------------------------------------- import Katip+import Katip.Core ------------------------------------------------------------------------------- @@ -27,11 +35,57 @@ tests = testGroup "Katip" [ testProperty "JSON cycle Item" $ \(i :: Item ()) ->- prop_json_cycle i+ prop_json_cycle i+ , testProperty "renderSeverity/textToSeverity cycle" $ \sev ->+ textToSeverity(renderSeverity sev) === Just sev+ , testProperty "processIDToText/textToProcessID cycle" $ \pid ->+ textToProcessID (processIDToText pid) === Just pid+ , testCase "processIDToText is just the number" $ do+ processIDToText 123 @?= "123"+ , logContextsTests ] -------------------------------------------------------------------------------+logContextsTests :: TestTree+logContextsTests = testGroup "logContexts"+ [+ testCase "overwrites with the right-hand side (right-bias)" $ do+ let l1 = liftPayload (SimpleLogPayload [("foo", AnyLogPayload ("a" :: Text))])+ l2 = liftPayload (SimpleLogPayload [("foo", AnyLogPayload ("b" :: Text))])+ l3 = liftPayload (SimpleLogPayload [("foo", AnyLogPayload ("c" :: Text))])+ both = l1 <> l2 <> l3+ toObject both @?= HM.singleton "foo" (String "c")+ , testCase "respects payloadKeys for each constituent payload" $ do+ let everything = liftPayload (SimpleLogPayload [("foo", AnyLogPayload ("a" :: Text))])+ conservative = liftPayload (ConservativePayload "always" "rarely")+ both = everything <> conservative+ payloadKeys V2 both @?= SomeKeys ["often_shown", "rarely_shown", "foo"]+ payloadKeys V1 both @?= SomeKeys ["often_shown", "foo"]+ ]+++-------------------------------------------------------------------------------+data ConservativePayload = ConservativePayload {+ oftenShown :: Text+ , rarelyShown :: Text+ }+++instance ToJSON ConservativePayload where+ toJSON ConservativePayload {..} = object ["often_shown" .= oftenShown+ ,"rarely_shown" .= rarelyShown]+++instance ToObject ConservativePayload+++instance LogItem ConservativePayload where+ payloadKeys V1 _ = SomeKeys ["often_shown"]+ payloadKeys V0 _ = SomeKeys []+ payloadKeys _ _ = AllKeys++------------------------------------------------------------------------------- prop_json_cycle :: (ToJSON a, FromJSON a, Eq a, Show a) => a -> Property prop_json_cycle a = eitherDecode (encode a) === Right a @@ -69,6 +123,9 @@ deriving instance Arbitrary Environment deriving instance Arbitrary ThreadIdText deriving instance Arbitrary CPid+#if !MIN_VERSION_base(4, 8, 0)+deriving instance Eq Loc+#endif deriving instance Eq LogStr deriving instance (Eq a) => Eq (Item a)
test/Katip/Tests/Scribes/Handle.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings #-} module Katip.Tests.Scribes.Handle ( tests ) where@@ -6,6 +6,7 @@ ------------------------------------------------------------------------------- import Control.Monad import Data.Aeson+import Data.Monoid import Data.Text (Text) import qualified Data.Text.IO as T import System.Directory@@ -27,9 +28,9 @@ runKatipT le $ logItem dummyLogItem "test" Nothing InfoS "test message" hClose h res <- readFile path- let pat = "\\[[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\\]\\[katip-test.test\\]\\[Info\\]\\[.+\\]\\[[[:digit:]]+\\]\\[ThreadId [[:digit:]]+\\]\\[note:some note\\] test message" :: String+ let pat = "\\[[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} [[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\\]\\[katip-test.test\\]\\[Info\\]\\[.+\\]\\[[[:digit:]]+\\]\\[ThreadId [[:digit:]]+\\]\\[note.deep:some note\\] test message" :: String let matches = res =~ pat- matches @?= True+ assertBool (res <> " did not match") matches ] @@ -40,7 +41,10 @@ instance ToJSON DummyLogItem where- toJSON (DummyLogItem n) = object ["note" .= n]+ toJSON (DummyLogItem n) = object+ [ "note" .= object [ "deep" .= n+ ]+ ] instance ToObject DummyLogItem