packages feed

micrologger 0.4.0.1 → 0.5.0.0

raw patch · 7 files changed

+119/−88 lines, 7 filesdep +bytestringdep +lensPVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring, lens

API changes (from Hackage documentation)

- LuminescentDreams.Logger: [logCmd_] :: Logger -> (Text -> IO ())
- LuminescentDreams.Logger: [lvl_] :: Logger -> LogLevel
- LuminescentDreams.Logger.Internal: LogDebug :: LogLevel
- LuminescentDreams.Logger.Internal: LogEmergency :: LogLevel
- LuminescentDreams.Logger.Internal: LogError :: LogLevel
- LuminescentDreams.Logger.Internal: LogInfo :: LogLevel
- LuminescentDreams.Logger.Internal: LogWarning :: LogLevel
- LuminescentDreams.Logger.Internal: Logger :: (Text -> IO ()) -> LogLevel -> Logger
- LuminescentDreams.Logger.Internal: [logCmd_] :: Logger -> (Text -> IO ())
- LuminescentDreams.Logger.Internal: [lvl_] :: Logger -> LogLevel
- LuminescentDreams.Logger.Internal: data LogLevel
- LuminescentDreams.Logger.Internal: data Logger
- LuminescentDreams.Logger.Internal: instance Data.Text.Buildable.Buildable LuminescentDreams.Logger.Internal.LogLevel
- LuminescentDreams.Logger.Internal: instance GHC.Classes.Eq LuminescentDreams.Logger.Internal.LogLevel
- LuminescentDreams.Logger.Internal: instance GHC.Classes.Ord LuminescentDreams.Logger.Internal.LogLevel
- LuminescentDreams.Logger.Internal: instance GHC.Show.Show LuminescentDreams.Logger.Internal.LogLevel
- LuminescentDreams.Logger.Internal: tzFormat :: String
+ LuminescentDreams.Logger: [_logApp] :: Logger -> Text
+ LuminescentDreams.Logger: [_logCmd] :: Logger -> (Text -> IO ())
+ LuminescentDreams.Logger: [_logLvl] :: Logger -> LogLevel
+ LuminescentDreams.Logger: [_logTags] :: Logger -> [Text]
+ LuminescentDreams.Logger.Standard: LogMsg :: LogLevel -> [(String, String)] -> String -> LogMsg
+ LuminescentDreams.Logger.Standard: data LogMsg
+ LuminescentDreams.Logger.Standard: logMsg_ :: Logger -> LogMsg -> IO ()
+ LuminescentDreams.Logger.Types: LogDebug :: LogLevel
+ LuminescentDreams.Logger.Types: LogEmergency :: LogLevel
+ LuminescentDreams.Logger.Types: LogError :: LogLevel
+ LuminescentDreams.Logger.Types: LogInfo :: LogLevel
+ LuminescentDreams.Logger.Types: LogWarning :: LogLevel
+ LuminescentDreams.Logger.Types: Logger :: (Text -> IO ()) -> LogLevel -> Text -> [Text] -> Logger
+ LuminescentDreams.Logger.Types: [_logApp] :: Logger -> Text
+ LuminescentDreams.Logger.Types: [_logCmd] :: Logger -> (Text -> IO ())
+ LuminescentDreams.Logger.Types: [_logLvl] :: Logger -> LogLevel
+ LuminescentDreams.Logger.Types: [_logTags] :: Logger -> [Text]
+ LuminescentDreams.Logger.Types: data LogLevel
+ LuminescentDreams.Logger.Types: data Logger
+ LuminescentDreams.Logger.Types: instance Data.Text.Buildable.Buildable LuminescentDreams.Logger.Types.LogLevel
+ LuminescentDreams.Logger.Types: instance GHC.Classes.Eq LuminescentDreams.Logger.Types.LogLevel
+ LuminescentDreams.Logger.Types: instance GHC.Classes.Ord LuminescentDreams.Logger.Types.LogLevel
+ LuminescentDreams.Logger.Types: instance GHC.Show.Show LuminescentDreams.Logger.Types.LogLevel
+ LuminescentDreams.Logger.Types: logApp :: Lens' Logger Text
+ LuminescentDreams.Logger.Types: logCmd :: Lens' Logger (Text -> IO ())
+ LuminescentDreams.Logger.Types: logLvl :: Lens' Logger LogLevel
+ LuminescentDreams.Logger.Types: logTags :: Lens' Logger [Text]
+ LuminescentDreams.Logger.Types: tzFormat :: String
- LuminescentDreams.Logger: Buffer :: (IORef Text) -> LogLevel -> LogConfig
+ LuminescentDreams.Logger: Buffer :: (IORef Text) -> LogLevel -> Text -> [Text] -> LogConfig
- LuminescentDreams.Logger: FileLog :: FilePath -> LogLevel -> LogConfig
+ LuminescentDreams.Logger: FileLog :: FilePath -> LogLevel -> Text -> [Text] -> LogConfig
- LuminescentDreams.Logger: Logger :: (Text -> IO ()) -> LogLevel -> Logger
+ LuminescentDreams.Logger: Logger :: (Text -> IO ()) -> LogLevel -> Text -> [Text] -> Logger
- LuminescentDreams.Logger: Stdout :: LogLevel -> LogConfig
+ LuminescentDreams.Logger: Stdout :: LogLevel -> Text -> [Text] -> LogConfig
- LuminescentDreams.Logger.JSON: formatMsgJs :: UTCTime -> LogLevel -> [(String, Value)] -> Text
+ LuminescentDreams.Logger.JSON: formatMsgJs :: Text -> [Text] -> UTCTime -> LogLevel -> [(String, Value)] -> Text
- LuminescentDreams.Logger.Standard: formatMsgStd :: UTCTime -> LogMsg -> Text
+ LuminescentDreams.Logger.Standard: formatMsgStd :: Text -> [Text] -> UTCTime -> LogMsg -> Text

Files

micrologger.cabal view
@@ -1,35 +1,47 @@ name:                micrologger-version:             0.4.0.1-synopsis:            A super simple logging module. Only for use for very simple projects.-description:         A super simple logging module. Only for use for very simple projects.+version:             0.5.0.0+synopsis:            A super simple logging module.+description:         A super simple logging module that primarily outputs json-formatted messages. homepage:            https://github.com/savannidgerinel/micrologger#readme license:             BSD3 license-file:        LICENSE author:              Savanni D'Gerinel-maintainer:          savanni@savannidgerinel.com-copyright:           2016 Savanni D'Gerinel+maintainer:          savanni@luminescent-dreams.com+copyright:           2016 - 2017 Savanni D'Gerinel category:            Web build-type:          Simple -- extra-source-files: cabal-version:       >=1.10 +flag dev+    description:        Turn on development settings+    manual:             True+    default:            False++ library-  hs-source-dirs:       src-  default-language:     Haskell2010-  ghc-options:          -Wall+    hs-source-dirs:     src+    default-language:   Haskell2010 -  exposed-modules:      LuminescentDreams.Logger-                        LuminescentDreams.Logger.Internal+    if flag(dev)+        ghc-options:    -Wall+    else +        ghc-options:    -Wall -Werror++    exposed-modules:    LuminescentDreams.Logger                         LuminescentDreams.Logger.JSON                         LuminescentDreams.Logger.Standard+                        LuminescentDreams.Logger.Types -  build-depends:          base          >= 4.7    && < 5-                        , aeson         >= 1.0    && < 1.1-                        , containers    >= 0.5.6  && < 0.6-                        , text          >= 1.2    && < 1.3-                        , text-format   >= 0.3    && < 0.4-                        , time          >= 1.5    && < 1.7-                        , transformers  >= 0.4    && < 0.6+    build-depends:        base          >= 4.7      && < 5+                        , aeson         >= 1.0      && < 1.1+                        , bytestring    >= 0.10     && < 0.11+                        , containers    >= 0.5.6    && < 0.6+                        , lens          >= 4.15     && < 4.16+                        , text          >= 1.2      && < 1.3+                        , text-format   >= 0.3      && < 0.4+                        , time          >= 1.5      && < 1.7+                        , transformers  >= 0.4      && < 0.6  test-suite micrologger-test   type:               exitcode-stdio-1.0
src/LuminescentDreams/Logger.hs view
@@ -11,27 +11,28 @@   )   where -import           LuminescentDreams.Logger.Internal+import           LuminescentDreams.Logger.Types import           LuminescentDreams.Logger.JSON        as X import           LuminescentDreams.Logger.Standard    as X  import           Data.Monoid import           Data.IORef                           (IORef, modifyIORef)-import qualified Data.Text.Lazy                       as T+import qualified Data.Text                            as T import           System.IO                            (IOMode(..), hPutStrLn, hFlush, withFile, stdout)  {- | Ordinary configurations for a file-based logger. -}-data LogConfig = Stdout LogLevel-               | Buffer (IORef T.Text) LogLevel-               | FileLog FilePath LogLevel+data LogConfig = Stdout LogLevel T.Text [T.Text]+               | Buffer (IORef T.Text) LogLevel T.Text [T.Text]+               | FileLog FilePath LogLevel T.Text [T.Text]   {- | Run an IO action with a log safely available. Logs will be properly closed in the case of an exception. Logging is meant to happen to a file, specified in LogConfig, so this may not be suitable if you want to log to a different resource. -} withLogger :: LogConfig -> (Logger -> IO a) -> IO a-withLogger (Stdout level) act =-  act (Logger (\m -> putStrLn (T.unpack m) >> hFlush stdout) level)-withLogger (Buffer ref level) act =-  act (Logger (\m -> modifyIORef ref (\buf -> buf <> m <> T.pack "\n")) level)-withLogger (FileLog path level) act =+withLogger (Stdout level app tags) act =+  act (Logger (\m -> putStrLn (T.unpack m) >> hFlush stdout) level app tags)+withLogger (Buffer ref level app tags) act =+  act (Logger (\m -> modifyIORef ref (\buf -> buf <> m <> T.pack "\n")) level app tags)+withLogger (FileLog path level app tags) act =   withFile path AppendMode $ \h ->-    act (Logger (\m -> hPutStrLn h (T.unpack m) >> hFlush h) level)+    act (Logger (\m -> hPutStrLn h (T.unpack m) >> hFlush h) level app tags)+
− src/LuminescentDreams/Logger/Internal.hs
@@ -1,31 +0,0 @@-{- | Internal definitions. Do not import directly. -}-module LuminescentDreams.Logger.Internal where--import qualified Data.Text.Buildable      as TFB-import qualified Data.Text.Lazy           as T--{- | An ordinary hierarchy of logging priorities. -}-data LogLevel = LogDebug-              | LogInfo-              | LogWarning-              | LogError-              | LogEmergency-              deriving (Eq, Ord, Show)--tzFormat :: String-tzFormat = "%Y-%m-%dT%H:%M:%S%Q%z"--{- | The primary data structure to contain a logger of any kind. -}-data Logger = Logger { logCmd_ :: (T.Text -> IO ())-                       -- ^ Any IO action that accepts the log message-                     , lvl_ :: LogLevel-                       -- ^ The minimum level at which a log message should be accepted-                     }--{- | Generate standard text representations of a log level. This is useful to the Standard logger but may not be interesting to any others. -}-instance TFB.Buildable LogLevel where-  build LogDebug      = TFB.build ("DEBUG" :: String)-  build LogInfo       = TFB.build ("INFO" :: String)-  build LogWarning    = TFB.build ("WARNING" :: String)-  build LogError      = TFB.build ("ERROR" :: String)-  build LogEmergency  = TFB.build ("EMERGENCY" :: String)
src/LuminescentDreams/Logger/JSON.hs view
@@ -6,28 +6,32 @@ module LuminescentDreams.Logger.JSON ( logMsgJs, formatMsgJs ) where  import           Control.Monad            (when)-import           Data.Monoid+import qualified Data.ByteString.Lazy     as BL import qualified Data.Aeson               as Aeson import qualified Data.Map                 as M+import           Data.Monoid import           Data.String import qualified Data.Text.Format         as TF-import qualified Data.Text.Lazy.Encoding  as TEnc+import qualified Data.Text                as T+import qualified Data.Text.Encoding       as TEnc+import qualified Data.Text.Lazy           as TL import qualified Data.Time                as Time-import qualified Data.Text.Lazy           as T -import           LuminescentDreams.Logger.Internal+import           LuminescentDreams.Logger.Types -{- | Log a message in LogZ format. This uses `formatMsgJs` to generate the actual format string. -} logMsgJs :: Logger -> LogLevel -> [(String, Aeson.Value)] -> IO ()-logMsgJs (Logger writer pri) lvl msg =+logMsgJs (Logger writer pri app_ tags_) lvl msg =     when (lvl >= pri) $ do         t <- Time.getCurrentTime-        writer $ formatMsgJs t lvl msg+        writer $ formatMsgJs app_ tags_ t lvl msg  {- | Format a message for LogZ JSON format. -}-formatMsgJs :: Time.UTCTime -> LogLevel -> [(String, Aeson.Value)] -> T.Text-formatMsgJs time level msg =+formatMsgJs :: T.Text -> [T.Text] -> Time.UTCTime -> LogLevel -> [(String, Aeson.Value)] -> T.Text+formatMsgJs application tags time level msg =   let msg_ = msg <> [ ("@timestamp", fromString $ Time.formatTime Time.defaultTimeLocale tzFormat time)-                    , ("@level", Aeson.String $ T.toStrict $ TF.format "{}" (TF.Only level))+                    , ("@level", Aeson.String $ TL.toStrict $ TF.format "{}" (TF.Only level))+                    , ("@tags", Aeson.toJSON tags)+                    , ("@app", Aeson.String application)                     ]-  in TEnc.decodeUtf8 $ Aeson.encode $ M.fromList msg_+  in TEnc.decodeUtf8 $ BL.toStrict $ Aeson.encode $ M.fromList msg_+
src/LuminescentDreams/Logger/Standard.hs view
@@ -2,17 +2,18 @@ {-# LANGUAGE MultiParamTypeClasses  #-} {-# LANGUAGE OverloadedStrings      #-} {-# OPTIONS_GHC -fno-warn-orphans   #-}-module LuminescentDreams.Logger.Standard ( logMsgStd, formatMsgStd ) where+module LuminescentDreams.Logger.Standard where  import           Control.Monad            (when) import           Data.Monoid import qualified Data.Text.Format         as TF-import qualified Data.Text.Lazy           as T+import qualified Data.Text                as T+import qualified Data.Text.Lazy           as TL import qualified Data.Text.Buildable      as TFB import qualified Data.Time                as Time import qualified Data.List                as List -import           LuminescentDreams.Logger.Internal+import           LuminescentDreams.Logger.Types   data LogMsg = LogMsg LogLevel [(String, String)] String@@ -21,23 +22,28 @@ logMsgStd l lvl tags text = logMsg_ l (LogMsg lvl tags text)  logMsg_ :: Logger -> LogMsg -> IO ()-logMsg_ (Logger writer pri) msg@(LogMsg lvl _ _) =+logMsg_ (Logger writer pri app tags) msg@(LogMsg lvl _ _) =     when (lvl >= pri) $ do         t <-  Time.getCurrentTime-        writer $ formatMsgStd t msg+        writer $ formatMsgStd app tags t msg  -formatMsgStd :: Time.UTCTime -> LogMsg -> T.Text-formatMsgStd t (LogMsg lvl tags text) =-  TF.format "{} {} {} {}" (Time.formatTime Time.defaultTimeLocale tzFormat t, lvl, tags, text)+formatMsgStd :: T.Text -> [T.Text] -> Time.UTCTime -> LogMsg -> T.Text+formatMsgStd _ _ t (LogMsg lvl tags text) =+    TL.toStrict $ TF.format "{} {} {} {}" ( Time.formatTime Time.defaultTimeLocale tzFormat t+                                          , lvl+                                          , tags+                                          , text+                                          )   instance TFB.Buildable (String, String) where-  build (name, value) = TFB.build $ "(" <> name <> ", " <> value <> ")"+    build (name, value) = TFB.build $ "(" <> name <> ", " <> value <> ")"  instance TFB.Buildable [(String, String)] where-  -- build lst = TFB.build "[" <> TFB.build `fmap` lst "]"-  build lst =-    mconcat $ [TFB.build ("[" :: String)]-           <> List.intersperse (TFB.build (", " :: String)) (TFB.build `fmap` lst)-           <> [TFB.build ("]" :: String)]+    -- build lst = TFB.build "[" <> TFB.build `fmap` lst "]"+    build lst =+        mconcat $ [TFB.build ("[" :: String)]+               <> List.intersperse (TFB.build (", " :: String)) (TFB.build `fmap` lst)+               <> [TFB.build ("]" :: String)]+
+ src/LuminescentDreams/Logger/Types.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE TemplateHaskell    #-}+{- | Logger type definitions -}+module LuminescentDreams.Logger.Types where++import           Control.Lens+import qualified Data.Text.Buildable      as TFB+import qualified Data.Text                as T++{- | An ordinary hierarchy of logging priorities. -}+data LogLevel = LogDebug+              | LogInfo+              | LogWarning+              | LogError+              | LogEmergency+              deriving (Eq, Ord, Show)++tzFormat :: String+tzFormat = "%Y-%m-%dT%H:%M:%S%Q%z"++{- | The primary data structure to contain a logger of any kind. -}+data Logger = Logger { _logCmd  :: (T.Text -> IO ())+                       -- ^ Any IO action that accepts the log message+                     , _logLvl  :: LogLevel+                     , _logApp  :: T.Text+                     , _logTags :: [T.Text]+                       -- ^ The minimum level at which a log message should be accepted+                     }++{- | Generate standard text representations of a log level. This is useful to the Standard logger but may not be interesting to any others. -}+instance TFB.Buildable LogLevel where+  build LogDebug      = TFB.build ("DEBUG" :: String)+  build LogInfo       = TFB.build ("INFO" :: String)+  build LogWarning    = TFB.build ("WARNING" :: String)+  build LogError      = TFB.build ("ERROR" :: String)+  build LogEmergency  = TFB.build ("EMERGENCY" :: String)++makeLenses ''Logger+
test/LogSpec.hs view
@@ -5,7 +5,7 @@ import           Data.Aeson       (Value(..), toJSON) import           Data.Monoid import qualified Data.IORef       as IORef-import qualified Data.Text.Lazy   as T+import qualified Data.Text        as T import           Test.Hspec  import           LuminescentDreams.Logger@@ -13,11 +13,12 @@ writeBuffer :: IORef.IORef [T.Text] -> T.Text -> IO () writeBuffer buffer text = IORef.modifyIORef' buffer (\lst -> lst <> [text]) + basicLogger :: Spec basicLogger = describe "demonstrate IO output" $ do   it "outputs in the standard format" $ do     logRef <- IORef.newIORef []-    let l = Logger (writeBuffer logRef) LogDebug+    let l = Logger (writeBuffer logRef) LogDebug "test" []     logMsgStd l LogInfo [("name", "value")] "message"     logMsgStd l LogInfo [("name", "value")] "message2"     IORef.readIORef logRef >>= flip forM_ (putStrLn . T.unpack)@@ -27,7 +28,7 @@ jsonLogger = describe "demonstrate the JSON logger with IO output" $ do   it "outputs in the JSON format" $ do     logRef <- IORef.newIORef []-    let l = Logger (writeBuffer logRef) LogDebug+    let l = Logger (writeBuffer logRef) LogDebug "test" []     logMsgJs l LogInfo [("name", String "value"), ("timing", toJSON (0.5 :: Float)), ("msg", String "message")]     logMsgJs l LogInfo [("name", String "value"), ("timing", toJSON (0.5 :: Float)), ("msg", String "message2")]     IORef.readIORef logRef >>= flip forM_ (putStrLn . T.unpack)@@ -39,7 +40,7 @@    it "outputs to a file buffer" $ do     logRef <- IORef.newIORef T.empty-    withLogger (Buffer logRef LogInfo) $ \l -> do+    withLogger (Buffer logRef LogInfo "test" []) $ \l -> do       logMsgStd l LogInfo [("name", "value")] "message"       logMsgStd l LogDebug [("name", "value")] "message2"       logMsgJs l LogDebug [("name", String "value"), ("timing", toJSON (0.5 :: Float)), ("msg", String "message")]