-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Batteries-included Structured Logging library -- -- Please see README.md @package Blammo @version 1.0.2.2 module Blammo.Logging.Colors data Colors Colors :: (Text -> Text) -> (Text -> Text) -> (Text -> Text) -> (Text -> Text) -> (Text -> Text) -> (Text -> Text) -> (Text -> Text) -> (Text -> Text) -> (Text -> Text) -> (Text -> Text) -> Colors [gray] :: Colors -> Text -> Text [black] :: Colors -> Text -> Text [cyan] :: Colors -> Text -> Text [magenta] :: Colors -> Text -> Text [blue] :: Colors -> Text -> Text [yellow] :: Colors -> Text -> Text [green] :: Colors -> Text -> Text [red] :: Colors -> Text -> Text [bold] :: Colors -> Text -> Text [dim] :: Colors -> Text -> Text getColors :: Bool -> Colors -- | Backwards-compatible extension to a simple LogLevel -- parser/filter -- -- Assume you are using this library/module to parse a LOG_LEVEL -- environment variable, which is used to filter your logs. -- -- Running, -- --
--   LOG_LEVEL=warn ./my-program
--   
-- -- Will do what you expect: filter all logging to only those messages -- at-or-above warn level. -- -- While, -- --
--   LOG_LEVEL=debug ./my-program
--   
-- -- Will enable debug logging throughout. -- -- This is all un-surprising and this module does not change behavior in -- this case whatsoever. But let's say that is entirely too noisy. -- Because you're using Amazonka and persistent, and have correctly -- integrated your main logging with them, you are now getting -- tons of spam from their very-chatty debug logs, and its -- drowning out the application debug logs you were hoping to see. -- -- Well, now can do this: -- --
--   LOG_LEVEL="debug,Amazonka:info,SQL:warn" ./my-program
--   
-- -- And suddenly your application's debug logs are standing out again, -- because everything from the Amazonka source is filtered to info and -- the SQL source is filtered to warn. -- -- The format parsed by readLogLevels is: -- --
--   [source:level, ...,]level[, source:level, ...]
--   
-- -- Where level defines the minimum level for anything not -- overridden by source. If you go on to add any -- source:level pairs, that will change the minimum level -- for messages from that source. module Blammo.Logging.LogSettings.LogLevels data LogLevels data LogLevel LevelDebug :: LogLevel LevelInfo :: LogLevel LevelWarn :: LogLevel LevelError :: LogLevel LevelOther :: Text -> LogLevel newLogLevels :: LogLevel -> [(LogSource, LogLevel)] -> LogLevels readLogLevels :: String -> Either String LogLevels shouldLogLevel :: LogLevels -> LogSource -> LogLevel -> Bool defaultLogLevels :: LogLevels instance GHC.Show.Show Blammo.Logging.LogSettings.LogLevels.LogLevels instance GHC.Classes.Eq Blammo.Logging.LogSettings.LogLevels.LogLevels module Blammo.Logging.LogSettings data LogSettings data LogLevels data LogDestination LogDestinationStdout :: LogDestination LogDestinationStderr :: LogDestination LogDestinationFile :: FilePath -> LogDestination data LogFormat LogFormatJSON :: LogFormat LogFormatTerminal :: LogFormat data LogColor LogColorAuto :: LogColor LogColorAlways :: LogColor LogColorNever :: LogColor readLogLevels :: String -> Either String LogLevels readLogDestination :: String -> Either String LogDestination readLogFormat :: String -> Either String LogFormat readLogColor :: String -> Either String LogColor defaultLogSettings :: LogSettings setLogSettingsLevels :: LogLevels -> LogSettings -> LogSettings setLogSettingsDestination :: LogDestination -> LogSettings -> LogSettings setLogSettingsFormat :: LogFormat -> LogSettings -> LogSettings setLogSettingsColor :: LogColor -> LogSettings -> LogSettings getLogSettingsLevels :: LogSettings -> LogLevels getLogSettingsDestination :: LogSettings -> LogDestination getLogSettingsFormat :: LogSettings -> LogFormat getLogSettingsColor :: LogSettings -> LogColor shouldLogLevel :: LogSettings -> LogSource -> LogLevel -> Bool shouldColorAuto :: Applicative m => LogSettings -> m Bool -> m Bool shouldColorHandle :: MonadIO m => LogSettings -> Handle -> m Bool -- | Produce a LogSettings by reading environment variables -- -- -- -- This module is meant to be imported qualified. -- --
--   import Blammo.Logging
--   import qualified Logging.LogSettings.Env as Env
--   
--   main :: IO ()
--   main = do
--     logger <- newLogger =<< Env.parse
--     runLoggerLoggingT logger $ -- ...
--   
module Blammo.Logging.LogSettings.Env parse :: IO LogSettings parser :: Parser Error LogSettings module Blammo.Logging.Test data LoggedMessages -- | This type is the Haskell representation of each JSON log message -- produced by this library. -- -- While we never interact with this type directly when logging messages -- with monad-logger-aeson, we may wish to use this type if we -- are parsing/processing log files generated by this library. data LoggedMessage LoggedMessage :: UTCTime -> LogLevel -> Maybe Loc -> Maybe LogSource -> KeyMap Value -> Text -> KeyMap Value -> LoggedMessage [loggedMessageTimestamp] :: LoggedMessage -> UTCTime [loggedMessageLevel] :: LoggedMessage -> LogLevel [loggedMessageLoc] :: LoggedMessage -> Maybe Loc [loggedMessageLogSource] :: LoggedMessage -> Maybe LogSource [loggedMessageThreadContext] :: LoggedMessage -> KeyMap Value [loggedMessageText] :: LoggedMessage -> Text [loggedMessageMeta] :: LoggedMessage -> KeyMap Value newLoggedMessages :: MonadIO m => m LoggedMessages appendLogStr :: MonadIO m => LoggedMessages -> LogStr -> m () getLoggedMessages :: MonadIO m => LoggedMessages -> m [Either String LoggedMessage] module Data.Aeson.Compat data Key fromText :: Text -> Key toText :: Key -> Text -- | A map from JSON key type Key to v. data KeyMap v -- | Construct an empty map. empty :: KeyMap v -- | Is the map empty? null :: KeyMap v -> Bool -- | Construct a map with a single element. singleton :: Key -> v -> KeyMap v -- | Construct a map with the supplied mappings. If the list contains -- duplicate mappings, the later mappings take precedence. fromList :: [(Key, v)] -> KeyMap v -- | Return a list of this map's keys and elements. -- -- The order is not stable. Use toAscList for stable ordering. toList :: KeyMap v -> [(Key, v)] -- | Colorful logging for humans -- -- Lines are formatted as -- --
--   {timestamp} [{level}] {message} {details}
--   
-- -- level is padded to 9 characters and message is -- padded to 31. This means things will align as long as values are -- shorter than that. Longer values will overflow (not be truncated). -- -- This format was designed to match Python's structlog package in -- its default configuration. module Blammo.Logging.Terminal reformatTerminal :: Bool -> LogLevel -> ByteString -> ByteString module Blammo.Logging.Logger data Logger class HasLogger env loggerL :: HasLogger env => Lens' env Logger newLogger :: MonadIO m => LogSettings -> m Logger getLoggerReformat :: Logger -> LogLevel -> ByteString -> ByteString getLoggerShouldLog :: Logger -> LogSource -> LogLevel -> Bool pushLogStrLn :: MonadIO m => Logger -> LogStr -> m () flushLogStr :: MonadIO m => Logger -> m () -- | Create a Logger that will capture log messages instead of -- logging them -- -- See Blammo.Logging.LoggedMessages for more details. newTestLogger :: MonadIO m => LogSettings -> m Logger -- | This type is the Haskell representation of each JSON log message -- produced by this library. -- -- While we never interact with this type directly when logging messages -- with monad-logger-aeson, we may wish to use this type if we -- are parsing/processing log files generated by this library. data LoggedMessage LoggedMessage :: UTCTime -> LogLevel -> Maybe Loc -> Maybe LogSource -> KeyMap Value -> Text -> KeyMap Value -> LoggedMessage [loggedMessageTimestamp] :: LoggedMessage -> UTCTime [loggedMessageLevel] :: LoggedMessage -> LogLevel [loggedMessageLoc] :: LoggedMessage -> Maybe Loc [loggedMessageLogSource] :: LoggedMessage -> Maybe LogSource [loggedMessageThreadContext] :: LoggedMessage -> KeyMap Value [loggedMessageText] :: LoggedMessage -> Text [loggedMessageMeta] :: LoggedMessage -> KeyMap Value -- | Return the logged messages if newTestLogger was used -- -- If not, the empty list is returned. getLoggedMessages :: (MonadIO m, MonadReader env m, HasLogger env) => m [Either String LoggedMessage] -- | getLoggedMessages but ignore any messages that fail to parse getLoggedMessagesLenient :: (MonadIO m, MonadReader env m, HasLogger env) => m [LoggedMessage] -- | getLoggedMessages but throwString if any messages failed -- to parse getLoggedMessagesUnsafe :: (HasCallStack, MonadIO m, MonadReader env m, HasLogger env) => m [LoggedMessage] -- | Deprecated: Internal function, will be removed in a future -- version getLoggerLoggerSet :: Logger -> LoggerSet instance Blammo.Logging.Logger.HasLogger Blammo.Logging.Logger.Logger module Blammo.Logging data LogSettings data LogLevel LevelDebug :: LogLevel LevelInfo :: LogLevel LevelWarn :: LogLevel LevelError :: LogLevel LevelOther :: Text -> LogLevel data LogDestination LogDestinationStdout :: LogDestination LogDestinationStderr :: LogDestination LogDestinationFile :: FilePath -> LogDestination data LogFormat LogFormatJSON :: LogFormat LogFormatTerminal :: LogFormat data LogColor LogColorAuto :: LogColor LogColorAlways :: LogColor LogColorNever :: LogColor defaultLogSettings :: LogSettings setLogSettingsLevels :: LogLevels -> LogSettings -> LogSettings setLogSettingsDestination :: LogDestination -> LogSettings -> LogSettings setLogSettingsFormat :: LogFormat -> LogSettings -> LogSettings setLogSettingsColor :: LogColor -> LogSettings -> LogSettings data Logger class HasLogger env loggerL :: HasLogger env => Lens' env Logger newLogger :: MonadIO m => LogSettings -> m Logger runLoggerLoggingT :: (MonadIO m, HasLogger env) => env -> LoggingT m a -> m a -- | A Message captures a textual component and a metadata -- component. The metadata component is a list of SeriesElem to -- support tacking on arbitrary structured data to a log message. -- -- With the OverloadedStrings extension enabled, Message -- values can be constructed without metadata fairly conveniently, just -- as if we were using Text directly: -- --
--   logDebug "Some log message without metadata"
--   
-- -- Metadata may be included in a Message via the :# -- constructor: -- --
--   logDebug $ "Some log message with metadata" :#
--     [ "bloorp" .= (42 :: Int)
--     , "bonk" .= ("abc" :: Text)
--     ]
--   
-- -- The mnemonic for the :# constructor is that the # -- symbol is sometimes referred to as a hash, a JSON object can be -- thought of as a hash map, and so with :# (and enough -- squinting), we are cons-ing a textual message onto a JSON -- object. Yes, this mnemonic isn't well-typed, but hopefully it still -- helps! data Message (:#) :: Text -> [SeriesElem] -> Message infixr 5 :# (.=) :: (KeyValue kv, ToJSON v) => Key -> v -> kv infixr 8 .= -- | A series of values that, when encoded, should be separated by commas. -- Since 0.11.0.0, the .= operator is overloaded to create -- either (Text, Value) or Series. You can use Series -- when encoding directly to a bytestring builder as in the following -- example: -- --
--   toEncoding (Person name age) = pairs ("name" .= name <> "age" .= age)
--   
data Series -- | A class for monads which provide for the ability to account for all -- possible exit points from a computation, and to mask asynchronous -- exceptions. Continuation-based monads are invalid instances of this -- class. -- -- Instances should ensure that, in the following code: -- --
--   fg = f `finally` g
--   
-- -- The action g is called regardless of what occurs within -- f, including async exceptions. Some monads allow f -- to abort the computation via other effects than throwing an exception. -- For simplicity, we will consider aborting and throwing an exception to -- be two forms of "throwing an error". -- -- If f and g both throw an error, the error thrown by -- fg depends on which errors we're talking about. In a monad -- transformer stack, the deeper layers override the effects of the inner -- layers; for example, ExceptT e1 (Except e2) a represents a -- value of type Either e2 (Either e1 a), so throwing both an -- e1 and an e2 will result in Left e2. If -- f and g both throw an error from the same layer, -- instances should ensure that the error from g wins. -- -- Effects other than throwing an error are also overriden by the deeper -- layers. For example, StateT s Maybe a represents a value of -- type s -> Maybe (a, s), so if an error thrown from -- f causes this function to return Nothing, any -- changes to the state which f also performed will be erased. -- As a result, g will see the state as it was before -- f. Once g completes, f's error will be -- rethrown, so g' state changes will be erased as well. This is -- the normal interaction between effects in a monad transformer stack. -- -- By contrast, lifted-base's version of finally always -- discards all of g's non-IO effects, and g never sees -- any of f's non-IO effects, regardless of the layer ordering -- and regardless of whether f throws an error. This is not the -- result of interacting effects, but a consequence of -- MonadBaseControl's approach. class MonadCatch m => MonadMask (m :: Type -> Type) -- | This function lets us register structured, contextual info for the -- duration of the provided action. All messages logged within the -- provided action will automatically include this contextual info. This -- function is thread-safe, as the contextual info is scoped to the -- calling thread only. -- -- This function is additive: if we nest calls to it, each nested call -- will add to the existing thread context. In the case of overlapping -- keys, the nested call's Pair value(s) will win. Whenever the -- inner action completes, the thread context is rolled back to its value -- set in the enclosing action. -- -- If we wish to include the existing thread context from one thread in -- another thread, we must register the thread context explicitly on that -- other thread. myThreadContext can be leveraged in this case. -- -- Registering thread context for messages can be useful in many -- scenarios. One particularly apt scenario is in wai -- middlewares. We can generate an ID for each incoming request then -- include it in the thread context. Now all messages subsequently logged -- from our endpoint handler will automatically include that request ID: -- --
--   import Control.Monad.Logger.Aeson ((.=), withThreadContext)
--   import Network.Wai (Middleware)
--   import qualified Data.UUID.V4 as UUID
--   
--   addRequestId :: Middleware
--   addRequestId app = \request sendResponse -> do
--     uuid <- UUID.nextRandom
--     withThreadContext ["requestId" .= uuid] do
--       app request sendResponse
--   
-- -- If we're coming from a Java background, it may be helpful for us to -- draw parallels between this function and log4j2's -- ThreadContext (or perhaps log4j's MDC). -- They all enable the same thing: setting some thread-local info that -- will be automatically pulled into each logged message. withThreadContext :: (MonadIO m, MonadMask m) => [Pair] -> m a -> m a -- | This function lets us retrieve the calling thread's thread context. -- For more detail, we can consult the docs for withThreadContext. -- -- Note that even though the type signature lists MonadThrow as a -- required constraint, the library guarantees that -- myThreadContext will never throw. myThreadContext :: (MonadIO m, MonadThrow m) => m (KeyMap Value) -- | A key/value pair for an Object. type Pair = (Key, Value) -- | A Monad which has the ability to log messages in some manner. class Monad m => MonadLogger (m :: Type -> Type) monadLoggerLog :: (MonadLogger m, ToLogStr msg) => Loc -> LogSource -> LogLevel -> msg -> m () -- | An extension of MonadLogger for the common case where the -- logging action is a simple IO action. The advantage of using -- this typeclass is that the logging function itself can be extracted as -- a first-class value, which can make it easier to manipulate monad -- transformer stacks, as an example. class (MonadLogger m, MonadIO m) => MonadLoggerIO (m :: Type -> Type) -- | Request the logging function itself. askLoggerIO :: MonadLoggerIO m => m (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -- | Monad transformer that adds a new logging function. data LoggingT (m :: Type -> Type) a -- | Logs a Message with the location provided by an implicit -- CallStack. logDebug :: (HasCallStack, MonadLogger m) => Message -> m () -- | See logDebug logInfo :: (HasCallStack, MonadLogger m) => Message -> m () -- | See logDebug logWarn :: (HasCallStack, MonadLogger m) => Message -> m () -- | See logDebug logError :: (HasCallStack, MonadLogger m) => Message -> m () -- | See logDebug logOther :: (HasCallStack, MonadLogger m) => LogLevel -> Message -> m () type LogSource = Text -- | See logDebugCS logDebugNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m () -- | See logDebugNS logInfoNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m () -- | See logDebugNS logWarnNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m () -- | See logDebugNS logErrorNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m () -- | See logDebugNS logOtherNS :: (HasCallStack, MonadLogger m) => LogSource -> LogLevel -> Message -> m () -- | Simplified out-of-the-box logging module Blammo.Logging.Simple -- | Construct a Logger configured via environment variables newLoggerEnv :: MonadIO m => m Logger -- | Construct a Logger configured via environment variables and use -- it runSimpleLoggingT :: MonadIO m => LoggingT m a -> m a module Network.Wai.Middleware.Logging -- | Add context to any logging done from the request-handling thread addThreadContext :: [Pair] -> Middleware -- | addThreadContext, but have the Request available addThreadContextFromRequest :: (Request -> [Pair]) -> Middleware -- | Log requests (more accurately, responses) as they happen -- -- In JSON format, logged messages look like: -- --
--   {
--     ...
--     message: {
--       text: "GET foobar => 200 OK",
--       meta: {
--         method: GET,
--         path: "foobar",
--         query: "?baz=bat&quix=quo",
--         status: {
--           code: 200,
--           message: OK
--         },
--         durationMs: 1322.2,
--         requestHeaders: {
--           Authorization: "***",
--           Accept: "text/html",
--           Cookie: "***"
--         },
--         responseHeaders: {
--           Set-Cookie: "***",
--           Expires: "never"
--         }
--       }
--     }
--   }
--   
requestLogger :: HasLogger env => env -> Middleware requestLoggerWith :: HasLogger env => Config -> env -> Middleware data Config defaultConfig :: Config -- | Change the source used for log messages -- -- Default is requestLogger. setConfigLogSource :: LogSource -> Config -> Config -- | Change how the destinationIp field is determined -- -- Default is looking up the x-real-ip header. setConfigGetDestinationIp :: (Request -> Maybe Text) -> Config -> Config