monad-log 0.1.0.0 → 0.1.1.0
raw patch · 8 files changed
+257/−32 lines, 8 filesdep ~aesondep ~basedep ~exceptions
Dependency ranges changed: aeson, base, exceptions, transformers
Files
- CHANGELOG.md +4/−0
- Control/Monad/Log.hs +47/−20
- Control/Monad/Log/Label.hs +6/−1
- Control/Monad/Log/LogLoc.hs +11/−1
- Control/Monad/Log/LogThreadId.hs +6/−1
- Control/Monad/Log/NameSpace.hs +6/−0
- README.md +151/−0
- monad-log.cabal +26/−9
+ CHANGELOG.md view
@@ -0,0 +1,4 @@+0.1.1.0+-------++Update haddock, fix build on GHC-7.6/7.8.
Control/Monad/Log.hs view
@@ -5,7 +5,19 @@ {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE CPP #-} +-- | This module provides a mtl style 'MonadLog' class and a concrete monad transformer 'LogT'.+--+-- If you are an application author, you can use 'LogT' transformer,+-- a specialized reader monad to inject 'Logger'.+--+-- If you are a library author, you should:+--+-- * make your monad stack an instance of 'MonadLog', usually you can do this by embedding a 'Logger' into your monad's reader part.+--+-- * provide a default formatter, and API to run with customized formatter.+-- module Control.Monad.Log ( -- * parametrized 'Logger' type Level(..)@@ -21,24 +33,17 @@ , makeDefaultJSONLogger , defaultFormatter , defaultJSONFormatter- -- * re-export from fast-logger- , module X- , LogStr- , toLogStr- , LogType(..) -- * 'MonadLog' class , MonadLog(..)- , localEnv , withFilterLevel , withEnv+ , localEnv -- * LogT, a concrete monad transformaer , LogT(..) , runLogTSafe , runLogTSafeBase , runLogT'- -- * re-export from text-show- , module TextShow- -- logging functions+ -- * logging functions , debug , info , warning@@ -49,8 +54,25 @@ , warning' , error' , critical'+ -- * re-export from text-show and fast-logger+ , LogStr+ , toLogStr+ , LogType(..)+ , FileLogSpec(..)+ , TimeFormat+ , FormattedTime+ , simpleTimeFormat+ , simpleTimeFormat'+ , module X ) where +#if !(MIN_VERSION_base(4,8,0))+import Control.Applicative+import Data.Monoid (Monoid)+#endif+#if MIN_VERSION_base(4,9,0)+import qualified Control.Monad.Fail as Fail+#endif import Control.Monad (when, liftM, ap) import Control.Monad.Catch (MonadMask, finally) import Control.Monad.Trans.Control (MonadBaseControl)@@ -73,15 +95,13 @@ import Control.Monad.Trans.Writer.Strict as Strict import System.Log.FastLogger-import System.Log.FastLogger.Date as X-import System.Log.FastLogger.File as X import Prelude hiding (log, error) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.ByteString.Builder as BB-import TextShow (TextShow, showt, showb)+import TextShow as X import qualified Data.Aeson as JSON import Data.Aeson (ToJSON, fromEncoding, (.=))@@ -144,11 +164,11 @@ -- | make a 'Logger' based on 'FastLogger'. makeLogger :: (MonadIO m)- => (Level -> FormattedTime -> env -> Text -> LogStr)- -> TimeFormat+ => (Level -> FormattedTime -> env -> Text -> LogStr) -- ^ formatter function+ -> TimeFormat -- ^ check "System.Log.FastLogger.Date" -> LogType- -> Level- -> env+ -> Level -- ^ filter level+ -> env -- ^ init environment -> m (Logger env) makeLogger fmt tfmt typ fltr env = liftIO $ do tc <- newTimeCache tfmt@@ -182,7 +202,7 @@ -- | a default JSON formatter with following format: ----- @{"level": LEVEL, "time": TIME, "env": ENV, msg: LOG MESSAGE }\\n@+-- @{"level": "LEVEL", "time": "TIME", "env": "ENV", "msg": "LOG MESSAGE" }\\n@ defaultJSONFormatter :: (ToJSON env) => Level -> FormattedTime -> env -> Text -> LogStr defaultJSONFormatter lvl time env msg = toLogStr . BB.toLazyByteString $ ( fromEncoding . JSON.pairs $@@ -196,8 +216,7 @@ -- | This is the main class for using logging function in this package. ----- provide an instance for 'MonadLog' to log within your monad stack--- a concrete transformmer 'LogT' is also provided.+-- provide an instance for 'MonadLog' to log within your monad stack. class (MonadIO m) => MonadLog env m | m -> env where askLogger :: m (Logger env) localLogger :: (Logger env -> Logger env) -> m a -> m a@@ -266,7 +285,7 @@ -- | A simple 'MonadLog' instance. ----- a reader monad which embed a 'Logger'.+-- a special reader monad which embed a 'Logger'. newtype LogT env m a = LogT { runLogT :: Logger env -> m a } instance Monad m => Functor (LogT env m) where@@ -287,6 +306,14 @@ let LogT f' = f a f' lgr {-# INLINE (>>=) #-}+ fail msg = lift (fail msg)+ {-# INLINE fail #-}++#if MIN_VERSION_base(4,9,0)+instance Fail.MonadFail m => Fail.MonadFail (LogT env m) where+ fail msg = lift (Fail.fail msg)+ {-# INLINE fail #-}+#endif instance (MonadFix m) => MonadFix (LogT r m) where mfix f = LogT $ \ r -> mfix $ \ a -> runLogT (f a) r
Control/Monad/Log/Label.hs view
@@ -1,12 +1,15 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-} module Control.Monad.Log.Label where import Control.Monad.Log+#if !(MIN_VERSION_base(4,8,0))+import Control.Applicative+#endif import Data.Aeson import Data.Text (Text)-import Data.Text.Internal.Builder (fromText) -- | Simple 'Label' environment for labelled logging. --@@ -21,7 +24,9 @@ instance ToJSON Label where toJSON (Label t) = toJSON t+#if MIN_VERSION_aeson(0,10,0) toEncoding (Label t) = toEncoding t+#endif instance FromJSON Label where parseJSON t = Label <$> parseJSON t
Control/Monad/Log/LogLoc.hs view
@@ -2,13 +2,16 @@ {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-} module Control.Monad.Log.LogLoc where import Control.Monad.Log+#if !(MIN_VERSION_base(4,8,0))+import Control.Applicative+#endif import Data.Text (Text) import qualified Data.Text as T-import Data.Text.Internal.Builder (fromText) import Data.Aeson import Data.Monoid ((<>)) @@ -35,8 +38,10 @@ instance ToJSON LogLoc where toJSON (LogLoc p m f l) = object ["filename" .= f, "module" .= m, "package" .= p, "line" .= l]+#if MIN_VERSION_aeson(0,10,0) toEncoding (LogLoc p m f l) = pairs ("filename" .= f <> "module" .= m <> "package" .= p <> "line" .= l)+#endif instance FromJSON LogLoc where parseJSON (Object v) = LogLoc <$>@@ -56,6 +61,11 @@ |] -- | Get current 'LogLoc'.+--+-- depending on how accurately you want to record source location,+-- you may want to use 'Logger' 's environment, or provide your own on every log.+--+-- example usage: @info' $myLogLoc "log message"@ myLogLoc :: Q Exp myLogLoc = [| $(TH.location >>= liftLogLoc) |]
Control/Monad/Log/LogThreadId.hs view
@@ -1,15 +1,18 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-} module Control.Monad.Log.LogThreadId where import Control.Monad.Log+#if !(MIN_VERSION_base(4,8,0))+import Control.Applicative+#endif import Control.Monad.IO.Class import Control.Concurrent import Data.Aeson import Data.Text (Text) import qualified Data.Text as T-import Data.Text.Internal.Builder (fromText) -- | a formatted 'LogThreadId'. --@@ -24,7 +27,9 @@ instance ToJSON LogThreadId where toJSON (LogThreadId t) = toJSON t+#if MIN_VERSION_aeson(0,10,0) toEncoding (LogThreadId t) = toEncoding t+#endif instance FromJSON LogThreadId where parseJSON t = LogThreadId <$> parseJSON t
Control/Monad/Log/NameSpace.hs view
@@ -1,9 +1,13 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-} module Control.Monad.Log.NameSpace where import Control.Monad.Log+#if !(MIN_VERSION_base(4,8,0))+import Control.Applicative+#endif import Data.Aeson import Data.Text (Text) import qualified Data.Text as T@@ -27,7 +31,9 @@ instance ToJSON NameSpace where toJSON (NameSpace t) = toJSON t+#if MIN_VERSION_aeson(0,10,0) toEncoding (NameSpace t) = toEncoding t+#endif instance FromJSON NameSpace where parseJSON t = NameSpace <$> parseJSON t
+ README.md view
@@ -0,0 +1,151 @@+A fast & simple logging monad+=============================++[](http://hackage.haskell.org/package/monad-log)+[](https://travis-ci.org/winterland1989/monad-log)++This package provide a mtl style `MonadLog` class and a concrete monad transformer `LogT`, the main difference between this package and monad-logger are:+++ Base monad has to be an instance of `MonadIO`.+++ Parametrized logging environment for extensibility.+++ Basic logging environment type(`Label`,`Loc`,`NameSpace`,`ThreadId`) are included, and you can easily make your own.+++ JSON logging built-in.+++ default to fast-logger backend, with good stdout and file support.++If you are an application author, you can use `LogT` transformer, a specialized reader monad to inject `Logger env`.++If you are a library author, you should:+++ make your monad stack an instance of 'MonadLog', usually you can do this by embedding `Logger env` into your monad's reader part.+++ provide a default formatter, and API to run with customized formatter.++Example+-------+++ A simple labelled logger:++```haskell+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Control.Monad.Log+import Control.Monad.Log.Label++-- Following log will be output to stdout:+-- [INFO] [25-Apr-2016 12:51:56] [main] This is simple log 1+-- [INFO] [25-Apr-2016 12:51:56] [foo] This is simple log 2++main :: IO ()+main = do+ logger <- makeDefaultLogger+ simpleTimeFormat'+ (LogStdout 4096)+ levelDebug+ (Label "main")++ runLogTSafe logger $ do+ info "This is simple log 1"++ withLabel (Label "foo") $ do+ info "This is simple log 2"++```+++ Logging with ThreadId:++```haskell+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Control.Monad.Log+import Control.Monad.IO.Class+import Control.Monad+import Control.Concurrent+import Control.Monad.Log.LogThreadId++-- Following log will be output to stdout:+-- [INFO] [25-Apr-2016 15:06:10] [ThreadId 671] This is simple log 1+-- [INFO] [25-Apr-2016 15:06:10] [ThreadId 674] This is simple log 2+-- [INFO] [25-Apr-2016 15:06:10] [ThreadId 675] This is simple log 2+-- [INFO] [25-Apr-2016 15:06:10] [ThreadId 676] This is simple log 2+-- [INFO] [25-Apr-2016 15:06:10] [ThreadId 677] This is simple log 2+-- [INFO] [25-Apr-2016 15:06:10] [ThreadId 678] This is simple log 2+-- [INFO] [25-Apr-2016 15:06:10] [ThreadId 679] This is simple log 2+...++main :: IO ()+main = do+ tid <- myLogThreadId+ logger <- makeDefaultLogger+ simpleTimeFormat'+ (LogStdout 4096)+ levelDebug+ tid++ runLogTSafe logger $ do+ info "This is simple log 1"++ replicateM_ 100 $+ forkIO . runLogT' logger . withMyLogThreadId $ do+ info "This is simple log 2"+```+++ Customized logging environment:++```haskell+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE FlexibleContexts #-}++module Main where++import Control.Monad.Log+import Control.Monad.Log.LogLoc+import Control.Monad.Log.NameSpace+import Data.Aeson.TH+import Data.Text (Text)++-- Following JSON log will be output to stdout:+-- {"level":"INFO","time":"25-Apr-2016 13:54:32"+-- ,"env":{"loc":{"filename":"Test.hs","module":"Test","package":"monad_GM54RwU2jZ84vGJIhnMYMH","line":33},"ns":["root"]}+-- ,"msg":"This is simple log 1"}+-- {"level":"INFO","time":"25-Apr-2016 13:54:32"+-- ,"env":{"loc":{"filename":"Test.hs","module":"Test","package":"monad_GM54RwU2jZ84vGJIhnMYMH","line":33},"ns":["foo","root"]}+-- ,"msg":"This is simple log 2"}++-- | Define your logging environment type.+-- To use 'defaultFomatter', provide a 'TextShow' instance+-- To use 'defaultJSONFomatter', provide a 'ToJSON' instance++data MyEnv = MyEnv {+ loc :: LogLoc -- This is shared by every log within one 'MonadLog'.+ , ns :: NameSpace+ } deriving (Show, Eq)++$(deriveJSON defaultOptions ''MyEnv)++subMyNS :: (MonadLog MyEnv m) => Text -> m a -> m a+subMyNS sub = localEnv $ \env -> env { ns = pushNameSpace sub (ns env) }++main :: IO ()+main = do+ logger <- makeDefaultJSONLogger+ simpleTimeFormat'+ (LogStdout 4096)+ levelDebug+ (MyEnv $myLogLoc (NameSpace ["root"]))++ runLogTSafe logger $ do+ info "This is simple log 1"++ subMyNS "foo" $ do+ info "This is simple log 2"++```
monad-log.cabal view
@@ -1,10 +1,27 @@--- Initial monad-log.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/- name: monad-log-version: 0.1.0.0+version: 0.1.1.0 synopsis: A simple and fast logging monad-description: A simple and fast logging monad+description: + This package provide a mtl style `MonadLog` class and a concrete monad transformer `LogT`, the main difference between this package and monad-logger are:+ .+ * Base monad has to be an instance of `MonadIO`.+ .+ * Parametrized logging environment for extensibility.+ .+ * Basic logging environment type(`Label`,`Loc`,`NameSpace`,`ThreadId`) are included, and you can easily make your own.+ .+ * JSON logging built-in.+ .+ * default to fast-logger backend, with good stdout and file support.+ .+ If you are an application author, you can use `LogT` transformer, it's just a specialized reader monad to inject `Logger env`.+ .+ If you are a library author, you should do following two things:+ .+ * make your monad stack an instance of 'MonadLog', usually you can do this by embedding `Logger env` into your monad's reader part.+ .+ * provide a default formatter, and API to run with customized formatter.+ license: MIT license-file: LICENSE author: winterland1989@@ -12,7 +29,7 @@ -- copyright: category: Development build-type: Simple--- extra-source-files: +extra-source-files: CHANGELOG.md README.md cabal-version: >=1.10 library@@ -24,7 +41,7 @@ , Control.Monad.Log.LogThreadId -- other-modules: -- other-extensions: - build-depends: base >=4.8 && <4.9+ build-depends: base >=4.6 && <5 , fast-logger >=2.4.5 && <2.5 , monad-control >=0.3 && <1.1 , lifted-base @@ -32,8 +49,8 @@ , bytestring , text , text-show- , transformers >=0.2 && <0.5- , aeson >= 0.10 && <0.12+ , transformers >=0.2+ , aeson >= 0.4 && <0.12 , template-haskell -- hs-source-dirs: