co-log-simple 1.1.1 → 1.2.0
raw patch · 7 files changed
+148/−50 lines, 7 filesdep +timedep ~co-logPVP ok
version bump matches the API change (PVP)
Dependencies added: time
Dependency ranges changed: co-log
API changes (from Hackage documentation)
- Colog.Simple.Message: Black :: Color
- Colog.Simple.Message: Blue :: Color
- Colog.Simple.Message: Cyan :: Color
- Colog.Simple.Message: Green :: Color
- Colog.Simple.Message: Magenta :: Color
- Colog.Simple.Message: Msg :: !sev -> !CallStack -> Text -> Msg sev
- Colog.Simple.Message: Red :: Color
- Colog.Simple.Message: White :: Color
- Colog.Simple.Message: Yellow :: Color
- Colog.Simple.Message: [msgSeverity] :: Msg sev -> !sev
- Colog.Simple.Message: [msgStack] :: Msg sev -> !CallStack
- Colog.Simple.Message: [msgText] :: Msg sev -> Text
- Colog.Simple.Message: data Msg sev
+ Colog.Simple: loggingDisabled :: forall (m :: Type -> Type). Applicative m => LogAction m Message
+ Colog.Simple.Message: str :: MonadIO m => Text -> RichMessage m -> m Text
+ Colog.Simple.Message: time :: MonadIO m => RichMessage m -> m Text
+ Colog.Simple.Message: timec :: MonadIO m => RichMessage m -> m Text
+ Colog.Simple.Message: timecf :: MonadIO m => String -> RichMessage m -> m Text
+ Colog.Simple.Message: timef :: MonadIO m => String -> RichMessage m -> m Text
+ Colog.Simple.Message: type RichMessage (m :: Type -> Type) = RichMsg m Message
- Colog.Simple: logger :: forall (m :: Type -> Type). MonadIO m => (Message -> Text) -> LogAction m Text -> Severity -> LogAction m Message
+ Colog.Simple: logger :: MonadIO m => (RichMessage m -> m Text) -> LogAction m Text -> Severity -> LogAction m Message
- Colog.Simple.Message: (%) :: Formatter -> Formatter -> Formatter
+ Colog.Simple.Message: (%) :: MonadIO m => Formatter m -> Formatter m -> Formatter m
- Colog.Simple.Message: (%+) :: Formatter -> Formatter -> Formatter
+ Colog.Simple.Message: (%+) :: MonadIO m => Formatter m -> Formatter m -> Formatter m
- Colog.Simple.Message: basicFmt :: Message -> Text
+ Colog.Simple.Message: basicFmt :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: colorFmt :: Message -> Text
+ Colog.Simple.Message: colorFmt :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: colorSevFmt :: Message -> Text
+ Colog.Simple.Message: colorSevFmt :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: colorSevStackFmt :: Message -> Text
+ Colog.Simple.Message: colorSevStackFmt :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: msg :: Message -> Text
+ Colog.Simple.Message: msg :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: msgc :: Message -> Text
+ Colog.Simple.Message: msgc :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: sev :: Message -> Text
+ Colog.Simple.Message: sev :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: sevc :: Message -> Text
+ Colog.Simple.Message: sevc :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: stack :: Message -> Text
+ Colog.Simple.Message: stack :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: stackc :: Message -> Text
+ Colog.Simple.Message: stackc :: MonadIO m => RichMessage m -> m Text
- Colog.Simple.Message: type Formatter = Message -> Text
+ Colog.Simple.Message: type Formatter (m :: Type -> Type) = RichMessage m -> m Text
Files
- CHANGELOG.md +10/−0
- README.md +15/−3
- co-log-simple.cabal +3/−2
- src/examples/Main.hs +11/−6
- src/lib/Colog/Simple.hs +19/−5
- src/lib/Colog/Simple/Message.hs +89/−33
- stack.yaml +1/−1
CHANGELOG.md view
@@ -1,3 +1,13 @@+1.2.0 (2025-09-10)++ * Added and adjusted some documentation+ * Some subtle formatter changes+ * Added str formatter for constant strings in log messages+ * Pushed stackage snapshot up to lts-24.9+ * Added timestamps to logging (via RichMessage/RichMsg)+ * Added date formatting capability to the date formatters++ 1.1.1 (2025-08-12) * Fixed incorrect API docs
README.md view
@@ -20,9 +20,20 @@ 2. I've often wanted different colors for severities which is much easier with co-log than hslogger 3. This library also includes some functions for formatting different parts of- a log message like the severity or the message itself. These are to be- composed together with the (%) and (%+) operators.+ a log message like the severity, stack info, or the message itself. These+ formatters can be composed together with the (%) and (%+) operators. +Additionally:++I found using the RichMsg/RichMessage types in co-log to be slightly on the+complicated side to use. This library integrates timestamping through those+types as well to make things easier while keeping the interface simple.++co-log-simple uses the ISO8601 with zone offset format for timestamps by+default which I like because it sorts. The time formatters in this library also+support custom format strings as defined in the Data.Time.Format module in the+base time library.+ For usage examples, see `src/examples/Main.hs` and the API docs for `Colog.Simple` @@ -32,7 +43,8 @@ Source code is available from Codeberg at the [co-log-simple](https://codeberg.org/dinofp/co-log-simple) project page. -Generate Haddock docs during development if using stack:+Handy command to generate Haddock docs during development if using stack. This+constrains doc generation to modules in the library: $ stack haddock --haddock --no-haddock-deps
co-log-simple.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: co-log-simple-version: 1.1.1+version: 1.2.0 synopsis: Simple enhancements for logging with co-log description: A library built upon co-log that makes constructing and using `LogAction`s simpler with some predefined formatters and a slightly enhanced@@ -59,7 +59,7 @@ -Wredundant-constraints build-depends: base >=3 && <5- , co-log >=0.6.0.2 && <0.7+ , co-log >=0.7.0.0 && <0.8 library import: lang@@ -74,6 +74,7 @@ , co-log-core >=0.3.2.1 && <0.4 , mtl >=2.3.1 && <3 , text >=2.0.2 && <2.2+ , time >=1.4 && <1.14 executable co-log-simple import: lang
src/examples/Main.hs view
@@ -4,15 +4,15 @@ where import Colog.Monad (usingLoggerT)-import Colog.Simple (LogAction, Message, Severity (Debug, Notice), (%), (%+),- logger, logInfo, logNotice, logTest, logTextStderr, logTextStdout, msg, msgc,- sevc, stack)+import Colog.Simple (Severity (Debug, Notice), (%), (%+), logger,+ loggingDisabled, logInfo, logNotice, logTest, logTextStderr, logTextStdout,+ msg, msgc, sevc, stack, str, time) main :: IO () main = do putStrLn "------------------------------------------"- usingLoggerT (logger (sevc % msg) logTextStdout Debug) $ do+ usingLoggerT (logger (sevc %+ msg) logTextStdout Debug) $ do logNotice "Examples of all Severity values" logTest @@ -28,11 +28,16 @@ logTest putStrLn "------------------------------------------"- usingLoggerT (logger (sevc % msg %+ stack) logTextStdout Debug) $ do+ usingLoggerT (logger (time %+ sevc %+ str "| " % msg) logTextStdout Debug) $ do+ logNotice "Timestamps are often useful"+ logTest++ putStrLn "------------------------------------------"+ usingLoggerT (logger (sevc %+ msg %+ stack) logTextStdout Debug) $ do logNotice "With call stack info" logTest putStrLn "------------------------------------------" -- Example of completely turning off logging- usingLoggerT (mempty :: LogAction IO Message) $+ usingLoggerT loggingDisabled $ logInfo "This message should never be shown"
src/lib/Colog/Simple.hs view
@@ -2,11 +2,15 @@ This module is for creating 'LogAction' instances that use the logging and formatting functions in this library. +A simple example:+ @ import Colog.Monad (usingLoggerT)-import Colog.Simple (Severity (..), (%), logger, logNotice, logTextStdout, msg, sevc)+import Colog.Simple (Severity (..), (%+), logger, logNotice, logTextStdout,+ msg, sevc, time) -usingLoggerT (logger (sevc % msg) logTextStdout Debug) $ logNotice "Take note of this!"+usingLoggerT (logger (time %+ sevc %+ msg) logTextStdout Debug)+ $ logNotice "Take note of this!" @ The 'LogAction' produced by 'logger' above is what you would put in your@@ -19,6 +23,7 @@ ( -- * Constructing LogAction loggers logger+ , loggingDisabled -- * Utility functions , logTest@@ -36,7 +41,8 @@ import Colog (LogAction) import Colog.Actions (logTextStderr, logTextStdout)-import Colog.Message (formatWith)+import Colog.Core.Action (cmapM)+import Colog.Message (defaultFieldMap, upgradeMessageAction) import Colog.Monad (HasLog (..), WithLog) import Control.Monad.Trans (MonadIO) import Data.Text (Text)@@ -47,11 +53,19 @@ -- | Construct a logging action logger :: MonadIO m- => (Message -> Text) -- ^ Format function+ => (RichMessage m -> m Text) -- ^ Format function -> LogAction m Text -- ^ Where log message output will go -> Severity -- ^ The severity level to filter at or above -> LogAction m Message-logger fmtFs targetAction sev' = setSeverity sev' . formatWith fmtFs $ targetAction+logger fmtFs targetAction sev'+ = setSeverity sev'+ . upgradeMessageAction defaultFieldMap+ $ cmapM fmtFs targetAction+++-- | Use this to completely disable logging+loggingDisabled :: Applicative m => LogAction m Message+loggingDisabled = mempty -- | Test function to generate messages with every severity in this library
src/lib/Colog/Simple/Message.hs view
@@ -1,32 +1,42 @@ {-| The workhorse module of this library. Here you will find types for working with this logging library along with functions for issuing log messages of various-severities. Also in this module are a small set of basic log output formatters.+severities. Also in this module are log output formatters for different parts+of a log message.++The time* formatters use the local time and time zone as reported by the+system. To change this to UTC or some other zone, use the TZ environment+variable, timedatectl or similar and that zone will be used in logging.+Example:++@TZ=UTC my-app-with-logging@ -} module Colog.Simple.Message ( -- * Types Formatter , Message+ , RichMessage -- * Functions for logging with a specific severity , logDebug, logInfo, logNotice, logWarning, logError -- * Functions for composing formatters , (%), (%+)+ , str -- * Message formatting functions- , sev, sevc, stack, stackc, msg, msgc+ , msg, msgc+ , sev, sevc+ , time, timec, timecf, timef+ , stack, stackc -- * Other functions , colorize , setSeverity -- * Re-exported from ansi-terminal- , Color (..)-- -- * Re-exported from co-log- , Msg (..)+ , Color -- * Deprecated message formatting functions , basicFmt, colorFmt, colorSevFmt, colorSevStackFmt@@ -34,9 +44,13 @@ where import Colog (LogAction, cfilter)-import Colog.Message (Msg (..), log, showSourceLoc)+import Colog.Message (Msg (..), RichMsg (..), fmtRichMessageCustomDefault, log,+ showSourceLoc) import Colog.Monad (WithLog)+import Control.Monad.Trans (MonadIO, liftIO) import Data.Text (Text, pack)+import Data.Time.Format (defaultTimeLocale, formatTime)+import Data.Time.LocalTime (getCurrentTimeZone, utcToZonedTime) import GHC.Stack (withFrozenCallStack) import Prelude hiding (log) import System.Console.ANSI (Color (..), ColorIntensity (Vivid),@@ -48,6 +62,7 @@ -- | The type of a Msg parameterized with the custom severity type in this -- library type Message = Msg Severity+type RichMessage m = RichMsg m Message -- | Log a message with 'Debug' severity@@ -84,11 +99,11 @@ showSeverity :: Severity -> Text-showSeverity Debug = "[Debug] "-showSeverity Info = "[Info] "-showSeverity Notice = "[Notice] "-showSeverity Warning = "[Warning] "-showSeverity Error = "[Error] "+showSeverity Debug = "[Debug] "+showSeverity Info = "[Info] "+showSeverity Notice = "[Notice] "+showSeverity Warning = "[Warning]"+showSeverity Error = "[Error] " colorForSeverity :: Severity -> Color@@ -100,50 +115,91 @@ -- | The type of functions which format 'Message's into 'Text'-type Formatter = Message -> Text+type Formatter m = RichMessage m -> m Text -- | Apply two formatters to a 'Message' and combine the resulting 'Text's. -- With apologies to the formatting library for stealing their operator!-(%) :: Formatter -> Formatter -> Formatter-f % g = \msg' -> f msg' <> g msg'+(%) :: MonadIO m => Formatter m -> Formatter m -> Formatter m+f % g = \msg' -> (<>) <$> f msg' <*> g msg' -- | Apply two formatters to a 'Message' and combine the resulting 'Text' -- output with a space between. -- Again, with apologies to the formatting library for stealing their operator!-(%+) :: Formatter -> Formatter -> Formatter-f %+ g = f % const " " % g+(%+) :: MonadIO m => Formatter m -> Formatter m -> Formatter m+f %+ g = f % (const $ pure " ") % g +-- | "Format" some text. Used to send some text to the logger. An example could+-- be spacing between other formatters.+str :: MonadIO m => Text -> RichMessage m -> m Text+str = const . pure+++-- | Format the time the log message was generated+time :: MonadIO m => RichMessage m -> m Text+time = timef "%Y-%m-%dT%H:%M:%S%z"+++-- | Format the time the log message was generated with the supplied format+-- string+--+-- For formatting docs see the Data.Time.Format module in the base time+-- library.+timef :: MonadIO m => String -> RichMessage m -> m Text+timef timeFmt rm = do+ zone <- liftIO $ getCurrentTimeZone+ fmtRichMessageCustomDefault rm ( \_ mbTime _ ->+ pack . maybe ""+ (formatTime defaultTimeLocale timeFmt . utcToZonedTime zone)+ $ mbTime )+++-- | Format the time the log message was generated with color based on the+-- 'Severity'+timec :: MonadIO m => RichMessage m -> m Text+timec rm@(RichMsg (Msg s _ _) _) = colorize (colorForSeverity s) <$> time rm+++-- | Format the time the log message was generated with color based on the+-- 'Severity' and with the supplied format string+--+-- For formatting docs see the Data.Time.Format module in the base time+-- library.+timecf :: MonadIO m => String -> RichMessage m -> m Text+timecf timeFmt rm@(RichMsg (Msg s _ _) _) = colorize (colorForSeverity s)+ <$> timef timeFmt rm++ -- | Format 'Severity'-sev :: Message -> Text-sev (Msg s _ _) = showSeverity s+sev :: MonadIO m => RichMessage m -> m Text+sev (RichMsg (Msg s _ _) _) = pure $ showSeverity s -- | Format 'Severity' with color based on the value-sevc :: Message -> Text-sevc (Msg s _ _) = colorize (colorForSeverity s) $ showSeverity s+sevc :: MonadIO m => RichMessage m -> m Text+sevc rm@(RichMsg (Msg s _ _) _) = colorize (colorForSeverity s) <$> sev rm -- | Format call stack info-stack :: Message -> Text-stack (Msg _ cs _) = showSourceLoc cs+stack :: MonadIO m => RichMessage m -> m Text+stack (RichMsg (Msg _ cs _) _) = pure $ showSourceLoc cs -- | Format call stack info with color based on the 'Severity'-stackc :: Message -> Text-stackc (Msg s cs _) = colorize (colorForSeverity s) $ showSourceLoc cs+stackc :: MonadIO m => RichMessage m -> m Text+stackc rm@(RichMsg (Msg s _ _) _) = colorize (colorForSeverity s) <$> stack rm -- | Format the log message-msg :: Message -> Text-msg (Msg _ _ m) = m+msg :: MonadIO m => RichMessage m -> m Text+msg (RichMsg (Msg _ _ m) _) = pure m -- | Format the log message with color based on the 'Severity'-msgc :: Message -> Text-msgc (Msg s _ m) = colorize (colorForSeverity s) m+msgc :: MonadIO m => RichMessage m -> m Text+msgc rm@(RichMsg (Msg s _ _) _) = colorize (colorForSeverity s) <$> msg rm -- | Filter log messages for greater than or equal to the given 'Severity'@@ -152,25 +208,25 @@ -- | No color formatting. Just the message, no severity label-basicFmt :: Message -> Text+basicFmt :: MonadIO m => RichMessage m -> m Text basicFmt = msg {-# DEPRECATED basicFmt "Use msg instead" #-} -- | Format with no severity labels but message colors for each severity-colorFmt :: Message -> Text+colorFmt :: MonadIO m => RichMessage m -> m Text colorFmt = msgc {-# DEPRECATED colorFmt "Use msgc instead" #-} -- | Format with colored severity labels and no color for the message-colorSevFmt :: Message -> Text+colorSevFmt :: MonadIO m => RichMessage m -> m Text colorSevFmt = sevc % msg {-# DEPRECATED colorSevFmt "Use (sevc % msg) instead" #-} -- | Format with colored severity labels, call stack info, and no color for the -- message-colorSevStackFmt :: Message -> Text+colorSevStackFmt :: MonadIO m => RichMessage m -> m Text colorSevStackFmt = sevc % stack %+ msg {-# DEPRECATED colorSevStackFmt "Use (sevc % stack %+ msg) instead" #-}
stack.yaml view
@@ -1,4 +1,4 @@-snapshot: lts-22.6+snapshot: lts-24.9 packages: - .