Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Synopsis
- data Message = Text :# [SeriesElem]
- data SeriesElem
- data LoggedMessage = LoggedMessage {}
- logDebug :: (HasCallStack, MonadLogger m) => Message -> m ()
- logInfo :: (HasCallStack, MonadLogger m) => Message -> m ()
- logWarn :: (HasCallStack, MonadLogger m) => Message -> m ()
- logError :: (HasCallStack, MonadLogger m) => Message -> m ()
- logOther :: (HasCallStack, MonadLogger m) => LogLevel -> Message -> m ()
- logDebugCS :: MonadLogger m => CallStack -> Message -> m ()
- logInfoCS :: MonadLogger m => CallStack -> Message -> m ()
- logWarnCS :: MonadLogger m => CallStack -> Message -> m ()
- logErrorCS :: MonadLogger m => CallStack -> Message -> m ()
- logOtherCS :: MonadLogger m => CallStack -> LogLevel -> Message -> m ()
- logDebugNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m ()
- logInfoNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m ()
- logWarnNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m ()
- logErrorNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m ()
- logOtherNS :: (HasCallStack, MonadLogger m) => LogSource -> LogLevel -> Message -> m ()
- logDebugN :: (HasCallStack, MonadLogger m) => Message -> m ()
- logInfoN :: (HasCallStack, MonadLogger m) => Message -> m ()
- logWarnN :: (HasCallStack, MonadLogger m) => Message -> m ()
- logErrorN :: (HasCallStack, MonadLogger m) => Message -> m ()
- logOtherN :: (HasCallStack, MonadLogger m) => LogLevel -> Message -> m ()
- withThreadContext :: (MonadIO m, MonadMask m) => [Pair] -> m a -> m a
- myThreadContext :: (MonadIO m, MonadThrow m) => m (KeyMap Value)
- runFileLoggingT :: (MonadIO m, MonadMask m) => FilePath -> LoggingT m a -> m a
- runHandleLoggingT :: (LogLevel -> Handle) -> LoggingT m a -> m a
- runStdoutLoggingT :: LoggingT m a -> m a
- runStderrLoggingT :: LoggingT m a -> m a
- runFastLoggingT :: LoggerSet -> LoggingT m a -> m a
- defaultOutput :: Handle -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
- handleOutput :: (LogLevel -> Handle) -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
- fastLoggerOutput :: LoggerSet -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
- defaultOutputWith :: OutputOptions -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
- defaultOutputOptions :: (LogLevel -> ByteString -> IO ()) -> OutputOptions
- data OutputOptions
- outputIncludeThreadId :: OutputOptions -> Bool
- outputBaseThreadContext :: OutputOptions -> [Pair]
- defaultLogStr :: UTCTime -> KeyMap Value -> Loc -> LogSource -> LogLevel -> LogStr -> LogStr
- defaultHandleFromLevel :: (Text -> Handle) -> LogLevel -> Handle
- (.=) :: (KeyValue kv, ToJSON v) => Key -> v -> kv
- fromLogStr :: LogStr -> ByteString
- data LogStr
- class ToLogStr msg where
- defaultLoc :: Loc
- mapNoLoggingT :: (m a -> n b) -> NoLoggingT m a -> NoLoggingT n b
- mapLoggingT :: (m a -> n b) -> LoggingT m a -> LoggingT n b
- filterLogger :: forall (m :: Type -> Type) a. (LogSource -> LogLevel -> Bool) -> LoggingT m a -> LoggingT m a
- withChannelLogger :: forall (m :: Type -> Type) a. (MonadBaseControl IO m, MonadIO m) => Int -> LoggingT m a -> LoggingT m a
- unChanLoggingT :: (MonadLogger m, MonadIO m) => Chan LogLine -> m void
- runChanLoggingT :: MonadIO m => Chan LogLine -> LoggingT m a -> m a
- execWriterLoggingT :: Functor m => WriterLoggingT m a -> m [LogLine]
- runWriterLoggingT :: Functor m => WriterLoggingT m a -> m (a, [LogLine])
- logOtherS :: Q Exp
- logErrorS :: Q Exp
- logWarnS :: Q Exp
- logInfoS :: Q Exp
- logDebugS :: Q Exp
- liftLoc :: Loc -> Q Exp
- logOtherSH :: Text -> Q Exp
- logErrorSH :: Q Exp
- logWarnSH :: Q Exp
- logInfoSH :: Q Exp
- logDebugSH :: Q Exp
- data LogLevel
- type LogSource = Text
- class Monad m => MonadLogger (m :: Type -> Type) where
- monadLoggerLog :: ToLogStr msg => Loc -> LogSource -> LogLevel -> msg -> m ()
- class (MonadLogger m, MonadIO m) => MonadLoggerIO (m :: Type -> Type) where
- newtype NoLoggingT (m :: Type -> Type) a = NoLoggingT {
- runNoLoggingT :: m a
- type LogLine = (Loc, LogSource, LogLevel, LogStr)
- newtype WriterLoggingT (m :: Type -> Type) a = WriterLoggingT {
- unWriterLoggingT :: m (a, DList LogLine)
- newtype LoggingT (m :: Type -> Type) a = LoggingT {}
- data Loc = Loc {}
Synopsis
monad-logger-aeson
provides structured JSON logging using monad-logger
's
interface. Specifically, it is intended to be a (largely) drop-in replacement
for monad-logger
's Control.Monad.Logger.CallStack module.
In brief, this program:
{-# LANGUAGE BlockArguments #-} {-# LANGUAGE OverloadedStrings #-} module Main ( main ) where import Control.Monad.Logger.Aeson doStuff :: (MonadLogger m) => Int -> m () doStuff x = do logDebug $ "Doing stuff" :# ["x" .= x] main :: IO () main = do runStdoutLoggingT do doStuff 42 logInfo "Done"
Would produce this output (formatted for readability here with jq
):
{ "time": "2022-05-15T20:52:15.5559417Z", "level": "debug", "location": { "package": "main", "module": "Main", "file": "app/readme-example.hs", "line": 11, "char": 3 }, "message": { "text": "Doing stuff", "meta": { "x": 42 } } } { "time": "2022-05-15T20:52:15.5560448Z", "level": "info", "location": { "package": "main", "module": "Main", "file": "app/readme-example.hs", "line": 17, "char": 5 }, "message": { "text": "Done" } }
For additional detail on the library, please see the remainder of these Haddocks and the following external resources:
Types
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!
Since: 0.1.0.0
Text :# [SeriesElem] infixr 5 |
data SeriesElem Source #
A single key-value pair, where the value is encoded JSON. This is a more
restricted version of Series
: a SeriesElem
is intended to encapsulate
exactly one key-value pair, whereas a Series
encapsulates zero or more
key-value pairs. SeriesElem
values can be created via (.=)
from aeson
.
While a SeriesElem
most often will map to a single pair, note that a
Semigroup
instance is available for performance's sake. The Semigroup
instance is useful when multiple pairs are grouped together and then shared
across multiple logging calls. In that case, the cost of combining the pairs
in the group must only be paid once.
Since: 0.3.0.0
Instances
KeyValue SeriesElem Source # | Since: 0.3.0.0 |
Defined in Control.Monad.Logger.Aeson.Internal (.=) :: ToJSON v => Key -> v -> SeriesElem # | |
Semigroup SeriesElem Source # | Since: 0.3.1.0 |
Defined in Control.Monad.Logger.Aeson.Internal (<>) :: SeriesElem -> SeriesElem -> SeriesElem # sconcat :: NonEmpty SeriesElem -> SeriesElem # stimes :: Integral b => b -> SeriesElem -> SeriesElem # |
data LoggedMessage Source #
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.
Since: 0.1.0.0
Instances
Logging functions
Implicit call stack, no LogSource
logDebug :: (HasCallStack, MonadLogger m) => Message -> m () Source #
logInfo :: (HasCallStack, MonadLogger m) => Message -> m () Source #
See logDebug
Since: 0.1.0.0
logWarn :: (HasCallStack, MonadLogger m) => Message -> m () Source #
See logDebug
Since: 0.1.0.0
logError :: (HasCallStack, MonadLogger m) => Message -> m () Source #
See logDebug
Since: 0.1.0.0
logOther :: (HasCallStack, MonadLogger m) => LogLevel -> Message -> m () Source #
See logDebug
Since: 0.1.0.0
Explicit call stack, no LogSource
logDebugCS :: MonadLogger m => CallStack -> Message -> m () Source #
logInfoCS :: MonadLogger m => CallStack -> Message -> m () Source #
See logDebugCS
Since: 0.1.0.0
logWarnCS :: MonadLogger m => CallStack -> Message -> m () Source #
See logDebugCS
Since: 0.1.0.0
logErrorCS :: MonadLogger m => CallStack -> Message -> m () Source #
See logDebugCS
Since: 0.1.0.0
logOtherCS :: MonadLogger m => CallStack -> LogLevel -> Message -> m () Source #
See logDebugCS
Since: 0.1.0.0
Implicit call stack, with LogSource
logDebugNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m () Source #
See logDebugCS
Since: 0.1.0.0
logInfoNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m () Source #
See logDebugNS
Since: 0.1.0.0
logWarnNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m () Source #
See logDebugNS
Since: 0.1.0.0
logErrorNS :: (HasCallStack, MonadLogger m) => LogSource -> Message -> m () Source #
See logDebugNS
Since: 0.1.0.0
logOtherNS :: (HasCallStack, MonadLogger m) => LogSource -> LogLevel -> Message -> m () Source #
See logDebugNS
Since: 0.1.0.0
Convenience aliases
logDebugN :: (HasCallStack, MonadLogger m) => Message -> m () Source #
logInfoN :: (HasCallStack, MonadLogger m) => Message -> m () Source #
See logDebugN
Since: 0.4.0.0
logWarnN :: (HasCallStack, MonadLogger m) => Message -> m () Source #
See logDebugN
Since: 0.4.0.0
logErrorN :: (HasCallStack, MonadLogger m) => Message -> m () Source #
See logDebugN
Since: 0.4.0.0
logOtherN :: (HasCallStack, MonadLogger m) => LogLevel -> Message -> m () Source #
See logDebugN
Since: 0.4.0.0
Thread context
withThreadContext :: (MonadIO m, MonadMask m) => [Pair] -> m a -> m a Source #
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.
Since: 0.1.0.0
myThreadContext :: (MonadIO m, MonadThrow m) => m (KeyMap Value) Source #
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.
Since: 0.1.0.0
LoggingT
runners
runFileLoggingT :: (MonadIO m, MonadMask m) => FilePath -> LoggingT m a -> m a Source #
Run a block using a MonadLogger
instance which appends to the specified
file.
Note that this differs from the monad-logger
version in its constraints.
We use the exceptions
package's MonadMask
here for bracketing, rather
than monad-control
.
Since: 0.1.0.0
runHandleLoggingT :: (LogLevel -> Handle) -> LoggingT m a -> m a Source #
Run a block using a MonadLogger
instance which prints to a Handle
determined by the log message's LogLevel
.
A common use case for this function is to log warn/error messages to stderr
and debug/info messages to stdout
in CLIs/tools (see
defaultHandleFromLevel
).
Since: 0.1.0.0
runStdoutLoggingT :: LoggingT m a -> m a Source #
Run a block using a MonadLogger
instance which prints to stdout
.
Since: 0.1.0.0
runStderrLoggingT :: LoggingT m a -> m a Source #
Run a block using a MonadLogger
instance which prints to stderr
.
Since: 0.1.0.0
runFastLoggingT :: LoggerSet -> LoggingT m a -> m a Source #
Run a block using a MonadLogger
instance which appends to the specified
LoggerSet
.
Since: 0.1.0.0
Utilities for defining our own loggers
defaultOutput :: Handle -> Loc -> LogSource -> LogLevel -> LogStr -> IO () Source #
A default implementation of the action that backs the monadLoggerLog
function. It accepts a file handle as the first argument and will log
incoming LogStr
values wrapped in the JSON structure prescribed by this
library.
This is used in the definition of runStdoutLoggingT
and
runStderrLoggingT
:
runStdoutLoggingT
::LoggingT
m a -> m arunStdoutLoggingT
=flip
runLoggingT
(defaultOutput
stdout
)
We can instead use defaultOutputWith
if we need more control of the output.
Since: 0.1.0.0
handleOutput :: (LogLevel -> Handle) -> Loc -> LogSource -> LogLevel -> LogStr -> IO () Source #
An implementation of the action that backs the monadLoggerLog
function,
where the Handle
destination for each log message is determined by the log
message's LogLevel
. This function will log incoming LogStr
values wrapped
in the JSON structure prescribed by this library.
This is used in the definition of runHandleLoggingT
:
runHandleLoggingT
:: (LogLevel
->Handle
) ->LoggingT
m a -> m arunHandleLoggingT
=flip
runLoggingT
.handleOutput
Since: 0.1.0.0
fastLoggerOutput :: LoggerSet -> Loc -> LogSource -> LogLevel -> LogStr -> IO () Source #
An implementation of the action that backs the monadLoggerLog
function,
where log messages are written to a provided LoggerSet
. This function will
log incoming LogStr
values wrapped in the JSON structure prescribed by this
library.
This is used in the definition of runFastLoggingT
:
runFastLoggingT
::LoggerSet
->LoggingT
m a -> m arunFastLoggingT
loggerSet =flip
runLoggingT
(fastLoggerOutput
loggerSet)
Since: 0.1.0.0
defaultOutputWith :: OutputOptions -> Loc -> LogSource -> LogLevel -> LogStr -> IO () Source #
This function is a lower-level helper for implementing the action that
backs the monadLoggerLog
function.
We should generally prefer defaultOutput
over this function, but this
function is available if we do need more control over our output.
Since: 0.1.0.0
defaultOutputOptions :: (LogLevel -> ByteString -> IO ()) -> OutputOptions Source #
Given an output action for log messages, this function will produce the
default recommended OutputOptions
.
Specific options can be overriden via record update syntax using
outputIncludeThreadId
, outputBaseThreadContext
, and friends.
Since: 0.1.0.0
data OutputOptions Source #
OutputOptions
is for use with
defaultOutputWith
and enables us to configure
the JSON output produced by this library.
We can get a hold of a value of this type via
defaultOutputOptions
.
Since: 0.1.0.0
outputIncludeThreadId :: OutputOptions -> Bool Source #
Controls whether or not the thread ID is included in each log message's thread context.
Default: False
Since: 0.1.0.0
outputBaseThreadContext :: OutputOptions -> [Pair] Source #
Allows for setting a "base" thread context, i.e. a set of Pair
that
will always be present in log messages.
If we subsequently use withThreadContext
to
register some thread context for our messages, if any of the keys in
those Pair
values overlap with the "base" thread context, then the
overlapped Pair
values in the "base" thread context will be overridden
for the duration of the action provided to
withThreadContext
.
Default: mempty
Since: 0.1.0.0
defaultLogStr :: UTCTime -> KeyMap Value -> Loc -> LogSource -> LogLevel -> LogStr -> LogStr Source #
Since: 0.1.0.0
defaultHandleFromLevel :: (Text -> Handle) -> LogLevel -> Handle Source #
This function maps the possible LogLevel
values to Handle
values.
Specifically, LevelDebug
and LevelInfo
map to stdout
, while LevelWarn
and LevelError
map to stderr
. The function is most useful for CLIs/tools
(see runHandleLoggingT
).
The input function discriminating Text
is used to determine the Handle
mapping for LevelOther
. For example, if we wish for all LevelOther
messages to be logged to stderr
, we can supply (const stderr)
as the
value for this input function.
Since: 0.1.0.0
Re-exports from aeson
Re-exports from monad-logger
fromLogStr :: LogStr -> ByteString #
Converting LogStr
to ByteString
.
Log message builder. Use (<>
) to append two LogStr in O(1).
Types that can be converted to a LogStr
. Instances for
types from the text
library use a UTF-8 encoding. Instances
for numerical types use a decimal encoding.
Instances
defaultLoc :: Loc #
dummy location, used with logWithoutLoc
Since: monad-logger-0.3.23
mapNoLoggingT :: (m a -> n b) -> NoLoggingT m a -> NoLoggingT n b #
Map the unwrapped computation using the given function.
Since: monad-logger-0.3.29
mapLoggingT :: (m a -> n b) -> LoggingT m a -> LoggingT n b #
Map the unwrapped computation using the given function.
Since: monad-logger-0.3.29
filterLogger :: forall (m :: Type -> Type) a. (LogSource -> LogLevel -> Bool) -> LoggingT m a -> LoggingT m a #
Only log messages passing the given predicate function.
This can be a convenient way, for example, to ignore debug level messages.
Since: monad-logger-0.3.13
:: forall (m :: Type -> Type) a. (MonadBaseControl IO m, MonadIO m) | |
=> Int | Number of messages to keep |
-> LoggingT m a | |
-> LoggingT m a |
Within the LoggingT
monad, capture all log messages to a bounded
channel of the indicated size, and only actually log them if there is an
exception.
Since: monad-logger-0.3.2
unChanLoggingT :: (MonadLogger m, MonadIO m) => Chan LogLine -> m void #
Read logging tuples from an unbounded channel and log them into a
MonadLoggerIO
monad, forever.
For use in a dedicated thread with a channel fed by runChanLoggingT
.
Since: monad-logger-0.3.17
runChanLoggingT :: MonadIO m => Chan LogLine -> LoggingT m a -> m a #
Run a block using a MonadLogger
instance which writes tuples to an
unbounded channel.
The tuples can be extracted (ie. in another thread) with unChanLoggingT
or a custom extraction funtion, and written to a destination.
Since: monad-logger-0.3.17
execWriterLoggingT :: Functor m => WriterLoggingT m a -> m [LogLine] #
Run a block using a MonadLogger
instance. Return logs in a list
| @since 0.3.28
runWriterLoggingT :: Functor m => WriterLoggingT m a -> m (a, [LogLine]) #
Run a block using a MonadLogger
instance. Return a value and logs in a list
| @since 0.3.28
Generates a function that takes a LogSource
, a level name and a Text
and logs a LevelOther
message. Usage:
$logOtherS "SomeSource" "My new level" "This is a log message"
Generates a function that takes a LogSource
and Text
and logs a LevelDebug
message. Usage:
$logDebugS "SomeSource" "This is a debug log message"
logOtherSH :: Text -> Q Exp #
Generates a function that takes a 'Show a => a' and logs a LevelOther
message. Usage:
$(logOtherSH "My new level") "This is a log message"
logErrorSH :: Q Exp #
See logDebugSH
See logDebugSH
See logDebugSH
logDebugSH :: Q Exp #
Generates a function that takes a 'Show a => a' and logs a LevelDebug
message. Usage:
$(logDebugSH) (Just "This is a debug log message")
Since: monad-logger-0.3.18
class Monad m => MonadLogger (m :: Type -> Type) where #
A Monad
which has the ability to log messages in some manner.
Nothing
Instances
class (MonadLogger m, MonadIO m) => MonadLoggerIO (m :: Type -> Type) where #
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.
Since: monad-logger-0.3.10
Nothing
askLoggerIO :: m (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) #
Request the logging function itself.
Since: monad-logger-0.3.10
Instances
newtype NoLoggingT (m :: Type -> Type) a #
Monad transformer that disables logging.
Since: monad-logger-0.2.4
NoLoggingT | |
|
Instances
newtype WriterLoggingT (m :: Type -> Type) a #
Since: monad-logger-0.3.28
WriterLoggingT | |
|
Instances
newtype LoggingT (m :: Type -> Type) a #
Monad transformer that adds a new logging function.
Since: monad-logger-0.2.2
Instances
Loc | |
|
Instances
Data Loc | |
Defined in Language.Haskell.TH.Syntax gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Loc -> c Loc # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Loc # dataTypeOf :: Loc -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Loc) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Loc) # gmapT :: (forall b. Data b => b -> b) -> Loc -> Loc # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Loc -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Loc -> r # gmapQ :: (forall d. Data d => d -> u) -> Loc -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Loc -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Loc -> m Loc # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Loc -> m Loc # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Loc -> m Loc # | |
Generic Loc | |
Show Loc | |
Eq Loc | |
Ord Loc | |
type Rep Loc | |
Defined in Language.Haskell.TH.Syntax type Rep Loc = D1 ('MetaData "Loc" "Language.Haskell.TH.Syntax" "template-haskell" 'False) (C1 ('MetaCons "Loc" 'PrefixI 'True) ((S1 ('MetaSel ('Just "loc_filename") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "loc_package") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String)) :*: (S1 ('MetaSel ('Just "loc_module") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: (S1 ('MetaSel ('Just "loc_start") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 CharPos) :*: S1 ('MetaSel ('Just "loc_end") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 CharPos))))) |