log4hs 0.0.7.0 → 0.1.0.0
raw patch · 8 files changed
+94/−20 lines, 8 files
Files
- log4hs.cabal +4/−2
- src/Logging/Aeson.hs +19/−14
- src/Logging/Types/Class/Handler.hs +2/−0
- src/Logging/Types/Handlers.hs +2/−0
- src/Logging/Types/Handlers/FileHandler.hs +41/−0
- src/Logging/Types/Handlers/StreamHandler.hs +0/−4
- src/System/IO/Extra.hs +7/−0
- test/Logging/AesonSpec.hs +19/−0
log4hs.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 14d30e39d3ff2113f4ac08f122aa6f61a676b9d34facaafce1bc794bbeda7e10+-- hash: a647fb460a908fafb35b6663c643cc259815b41a600dce95f217343328a72f6c name: log4hs-version: 0.0.7.0+version: 0.1.0.0 synopsis: A python logging style log library description: Please see the http://hackage.haskell.org/package/log4hs category: logging@@ -37,12 +37,14 @@ Logging.Types.Filter Logging.Types.Formatter Logging.Types.Handlers+ Logging.Types.Handlers.FileHandler Logging.Types.Handlers.StreamHandler Logging.Types.Level Logging.Types.Logger Logging.Types.Manager Logging.Types.Record Logging.Types.Sink+ System.IO.Extra Paths_log4hs hs-source-dirs: src
src/Logging/Aeson.hs view
@@ -17,6 +17,7 @@ import Data.Aeson.Types (Parser, typeMismatch) import Data.Default import Data.Generics.Product.Typed+import Data.IORef import qualified Data.Map.Lazy as M import System.Directory import System.FilePath@@ -27,13 +28,6 @@ import Logging.Utils -mapAp :: (Applicative f1, Applicative f2) => f1 (a -> b) -> f2 a -> (f1 (f2 b))-mapAp f x = ((<*> x) . pure) <$> f--mapAp2 :: (Applicative f1, Applicative f2) => f1 (a -> b -> c) -> f2 a -> f2 b -> (f1 (f2 c))-mapAp2 f x y = ((<*> y). (<*> x) . pure) <$> f-- {- $aesondoc By using 'Data.Aeson', we can decode json string into 'Manager'.@@ -81,7 +75,7 @@ Note: Besides some common field, handler's other fields depend on its type. @- -- a standard format+ -- StreamHandler { \"type\": \"StreamHandler\", \"stream\": \"stderr\",@@ -90,7 +84,7 @@ \"formatter\": \"default\", } - -- FileHandler is just a StreamHandler, the stream is created by openFile+ -- FileHandler { \"type\": \"FileHandler\", \"file\": \"./default.log\",@@ -143,7 +137,7 @@ parseJSON invalid = typeMismatch "Object" invalid -instance FromJSON (StreamHandler) where+instance FromJSON StreamHandler where parseJSON = withObject "StreamHandler" $ \v -> StreamHandler <$> (parseStream <$> (v .:? "stream" .!= "stderr")) <*> v .:? "level" .!= def@@ -156,6 +150,19 @@ parseStream _ = error "Logging.Aeson: no parse (stream)" +instance FromJSON (IO FileHandler) where+ parseJSON = withObject "FileHandler" $ \v -> do+ file <- v .:? "file" .!= "log4hs.log"+ encoding <- v .:? "encoding" .!= (show utf8)+ level <- v .:? "level" .!= def+ filterer <- v .:? "filterer" .!= []+ formatter <- v .:? "formatter" .!= def+ return $ do+ stream <- newIORef undefined+ encoding' <- mkTextEncoding encoding+ return $ FileHandler stream file encoding' level filterer formatter++ instance FromJSON (IO SomeHandler) where parseJSON = withObject "Handler" $ \v -> (v .: "type") >>= (`parseHandler` v) where@@ -164,10 +171,8 @@ hdl <- parseJSON (Object v) return $ return $ toHandler (hdl :: StreamHandler) parseHandler "FileHandler" v = do- hdl <- parseJSON (Object v)- file <- v .: "file" .!= "default.log"- return $ openLogFile file utf8 >>= \stream -> return $- toHandler (hdl {stream = stream} :: StreamHandler)+ hdlIo <- parseJSON (Object v)+ return $ toHandler <$> (hdlIo :: IO FileHandler) instance FromJSON (M.Map String Formatter -> IO SomeHandler) where
src/Logging/Types/Class/Handler.hs view
@@ -40,9 +40,11 @@ (SomeHandler h1) == h2 = Just h1 == fromHandler h2 instance Handler SomeHandler where+ open (SomeHandler h) = open h emit (SomeHandler h) = emit h flush (SomeHandler h) = flush h close (SomeHandler h) = close h+ handle (SomeHandler h) = handle h fromHandler = Just . id toHandler = id
src/Logging/Types/Handlers.hs view
@@ -1,5 +1,7 @@ module Logging.Types.Handlers ( module Logging.Types.Handlers.StreamHandler+ , module Logging.Types.Handlers.FileHandler ) where +import Logging.Types.Handlers.FileHandler import Logging.Types.Handlers.StreamHandler
+ src/Logging/Types/Handlers/FileHandler.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE RecordWildCards #-}++module Logging.Types.Handlers.FileHandler+ ( FileHandler(..)+ ) where++import Data.IORef+import GHC.Generics+import System.IO++import Logging.Types.Class+import Logging.Types.Filter+import Logging.Types.Formatter+import Logging.Types.Level+import Logging.Utils+import System.IO.Extra+++-- | A handler type which writes logging records, appropriately formatted,+-- to a file.+--+data FileHandler = FileHandler { stream :: IORef Handle+ , file :: FilePath+ , encoding :: TextEncoding+ , level :: Level+ , filterer :: Filterer+ , formatter :: Formatter+ } deriving (Generic, Eq)++instance Handler FileHandler where+ open FileHandler{..} = atomicWriteIORef stream =<< openLogFile file encoding++ emit self@FileHandler{..} rcd = do+ flip hPutStrLn (format formatter rcd) =<< readIORef stream+ flush self++ flush FileHandler{..}= hFlush =<< readIORef stream++ close FileHandler{..} = hClose =<< readIORef stream
src/Logging/Types/Handlers/StreamHandler.hs view
@@ -17,10 +17,6 @@ -- | A handler type which writes logging records, appropriately formatted, -- to a stream. ----- Note that this class does not close the stream when the stream is a--- terminal device, e.g. 'stderr' and 'stdout'.------ Note: 'FileHandler' is an alias of 'StreamHandler' data StreamHandler = StreamHandler { stream :: Handle , level :: Level , filterer :: Filterer
+ src/System/IO/Extra.hs view
@@ -0,0 +1,7 @@+module System.IO.Extra where++import System.IO+++instance Eq TextEncoding where+ e1 == e2 = show e1 == show e2
test/Logging/AesonSpec.hs view
@@ -85,6 +85,25 @@ filterer == [Filter "Module.Submodule"] `shouldBe` True formatter == def {fmt = "default"} `shouldBe` True + it "decode FileHandler" $ do+ FileHandler{..} <- fromJust $ decode $ encode $+ [aesonQQ|+ {+ "type": "FileHandler",+ "file": "myapp.log",+ "encoding": "UTF-16",+ "level": "INFO",+ "filterer": ["Module.Submodule"],+ "formatter": "default"+ }+ |]++ file `shouldBe` "myapp.log"+ encoding `shouldBe` utf16+ level `shouldBe` "INFO"+ filterer == [Filter "Module.Submodule"] `shouldBe` True+ formatter == def {fmt = "default"} `shouldBe` True+ it "decode (formatters -> SomeHandler)" $ do let simple = def {fmt = "%(logger)s: %(message)s"} func = fromJust $ decode $ encode