{-# LANGUAGE RankNTypes #-}
module GHC.Utils.Logger
( Logger
, HasLogger (..)
, ContainsLogger (..)
, initLogger
, LogAction
, DumpAction
, TraceAction
, DumpFormat (..)
, popLogHook
, pushLogHook
, popDumpHook
, pushDumpHook
, popTraceHook
, pushTraceHook
, makeThreadSafe
, LogFlags (..)
, defaultLogFlags
, log_dopt
, log_set_dopt
, setLogFlags
, updateLogFlags
, logFlags
, logHasDumpFlag
, logVerbAtLeast
, jsonLogAction
, putLogMsg
, defaultLogAction
, defaultLogActionHPrintDoc
, defaultLogActionHPutStrDoc
, logMsg
, logDumpMsg
, defaultDumpAction
, putDumpFile
, putDumpFileMaybe
, putDumpFileMaybe'
, withDumpFileHandle
, touchDumpFile
, logDumpFile
, defaultTraceAction
, putTraceMsg
, loggerTraceFlushUpdate
, loggerTraceFlush
, logTraceMsg
)
where
import GHC.Prelude
import GHC.Driver.Flags
import GHC.Types.Error
import GHC.Types.SrcLoc
import qualified GHC.Utils.Ppr as Pretty
import GHC.Utils.Outputable
import GHC.Utils.Json
import GHC.Utils.Panic
import GHC.Data.EnumSet (EnumSet)
import qualified GHC.Data.EnumSet as EnumSet
import System.Directory
import System.FilePath ( takeDirectory, (</>) )
import qualified Data.Map.Strict as Map
import Data.Map.Strict (Map)
import Data.List (stripPrefix)
import Data.Time
import System.IO
import Control.Monad
import Control.Concurrent.MVar
import System.IO.Unsafe
import Debug.Trace (trace)
import GHC.Platform.Ways
data LogFlags = LogFlags
{ LogFlags -> SDocContext
log_default_user_context :: SDocContext
, LogFlags -> SDocContext
log_default_dump_context :: SDocContext
, LogFlags -> EnumSet DumpFlag
log_dump_flags :: !(EnumSet DumpFlag)
, LogFlags -> Bool
log_show_caret :: !Bool
, LogFlags -> Bool
log_show_warn_groups :: !Bool
, LogFlags -> Bool
log_enable_timestamps :: !Bool
, LogFlags -> Bool
log_dump_to_file :: !Bool
, LogFlags -> Maybe FilePath
log_dump_dir :: !(Maybe FilePath)
, LogFlags -> FilePath
log_dump_prefix :: !FilePath
, LogFlags -> Maybe FilePath
log_dump_prefix_override :: !(Maybe FilePath)
, LogFlags -> Bool
log_with_ways :: !Bool
, LogFlags -> Bool
log_enable_debug :: !Bool
, LogFlags -> Int
log_verbosity :: !Int
, LogFlags -> Maybe Ways
log_ways :: !(Maybe Ways)
}
defaultLogFlags :: LogFlags
defaultLogFlags :: LogFlags
defaultLogFlags = LogFlags
{ log_default_user_context :: SDocContext
log_default_user_context = SDocContext
defaultSDocContext
, log_default_dump_context :: SDocContext
log_default_dump_context = SDocContext
defaultSDocContext
, log_dump_flags :: EnumSet DumpFlag
log_dump_flags = EnumSet DumpFlag
forall a. EnumSet a
EnumSet.empty
, log_show_caret :: Bool
log_show_caret = Bool
True
, log_show_warn_groups :: Bool
log_show_warn_groups = Bool
True
, log_enable_timestamps :: Bool
log_enable_timestamps = Bool
True
, log_dump_to_file :: Bool
log_dump_to_file = Bool
False
, log_dump_dir :: Maybe FilePath
log_dump_dir = Maybe FilePath
forall a. Maybe a
Nothing
, log_dump_prefix :: FilePath
log_dump_prefix = FilePath
""
, log_dump_prefix_override :: Maybe FilePath
log_dump_prefix_override = Maybe FilePath
forall a. Maybe a
Nothing
, log_with_ways :: Bool
log_with_ways = Bool
True
, log_enable_debug :: Bool
log_enable_debug = Bool
False
, log_verbosity :: Int
log_verbosity = Int
0
, log_ways :: Maybe Ways
log_ways = Maybe Ways
forall a. Maybe a
Nothing
}
log_dopt :: DumpFlag -> LogFlags -> Bool
log_dopt :: DumpFlag -> LogFlags -> Bool
log_dopt = (LogFlags -> Int)
-> (LogFlags -> EnumSet DumpFlag) -> DumpFlag -> LogFlags -> Bool
forall a.
(a -> Int) -> (a -> EnumSet DumpFlag) -> DumpFlag -> a -> Bool
getDumpFlagFrom LogFlags -> Int
log_verbosity LogFlags -> EnumSet DumpFlag
log_dump_flags
log_set_dopt :: DumpFlag -> LogFlags -> LogFlags
log_set_dopt :: DumpFlag -> LogFlags -> LogFlags
log_set_dopt DumpFlag
f LogFlags
logflags = LogFlags
logflags { log_dump_flags = EnumSet.insert f (log_dump_flags logflags) }
logHasDumpFlag :: Logger -> DumpFlag -> Bool
logHasDumpFlag :: Logger -> DumpFlag -> Bool
logHasDumpFlag Logger
logger DumpFlag
f = DumpFlag -> LogFlags -> Bool
log_dopt DumpFlag
f (Logger -> LogFlags
logFlags Logger
logger)
logVerbAtLeast :: Logger -> Int -> Bool
logVerbAtLeast :: Logger -> Int -> Bool
logVerbAtLeast Logger
logger Int
v = LogFlags -> Int
log_verbosity (Logger -> LogFlags
logFlags Logger
logger) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
v
updateLogFlags :: Logger -> (LogFlags -> LogFlags) -> Logger
updateLogFlags :: Logger -> (LogFlags -> LogFlags) -> Logger
updateLogFlags Logger
logger LogFlags -> LogFlags
f = Logger -> LogFlags -> Logger
setLogFlags Logger
logger (LogFlags -> LogFlags
f (Logger -> LogFlags
logFlags Logger
logger))
setLogFlags :: Logger -> LogFlags -> Logger
setLogFlags :: Logger -> LogFlags -> Logger
setLogFlags Logger
logger LogFlags
flags = Logger
logger { logFlags = flags }
type LogAction = LogFlags
-> MessageClass
-> SrcSpan
-> SDoc
-> IO ()
type DumpAction = LogFlags
-> PprStyle
-> DumpFlag
-> String
-> DumpFormat
-> SDoc
-> IO ()
type TraceAction a = LogFlags -> String -> SDoc -> a -> a
data DumpFormat
= FormatHaskell
| FormatCore
| FormatSTG
| FormatByteCode
| FormatCMM
| FormatASM
| FormatC
| FormatLLVM
| FormatJS
| FormatText
deriving (Int -> DumpFormat -> ShowS
[DumpFormat] -> ShowS
DumpFormat -> FilePath
(Int -> DumpFormat -> ShowS)
-> (DumpFormat -> FilePath)
-> ([DumpFormat] -> ShowS)
-> Show DumpFormat
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DumpFormat -> ShowS
showsPrec :: Int -> DumpFormat -> ShowS
$cshow :: DumpFormat -> FilePath
show :: DumpFormat -> FilePath
$cshowList :: [DumpFormat] -> ShowS
showList :: [DumpFormat] -> ShowS
Show,DumpFormat -> DumpFormat -> Bool
(DumpFormat -> DumpFormat -> Bool)
-> (DumpFormat -> DumpFormat -> Bool) -> Eq DumpFormat
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DumpFormat -> DumpFormat -> Bool
== :: DumpFormat -> DumpFormat -> Bool
$c/= :: DumpFormat -> DumpFormat -> Bool
/= :: DumpFormat -> DumpFormat -> Bool
Eq)
type DumpCache = MVar (Map FilePath (MVar ()))
data Logger = Logger
{ Logger -> [LogAction -> LogAction]
log_hook :: [LogAction -> LogAction]
, Logger -> [DumpAction -> DumpAction]
dump_hook :: [DumpAction -> DumpAction]
, Logger -> forall a. [TraceAction a -> TraceAction a]
trace_hook :: forall a. [TraceAction a -> TraceAction a]
, Logger -> DumpCache
generated_dumps :: DumpCache
, Logger -> IO ()
trace_flush :: IO ()
, Logger -> LogFlags
logFlags :: !LogFlags
}
loggerTraceFlushUpdate :: Logger -> (IO () -> IO ()) -> Logger
loggerTraceFlushUpdate :: Logger -> (IO () -> IO ()) -> Logger
loggerTraceFlushUpdate Logger
logger IO () -> IO ()
upd = Logger
logger { trace_flush = upd (trace_flush logger) }
loggerTraceFlush :: Logger -> IO ()
loggerTraceFlush :: Logger -> IO ()
loggerTraceFlush Logger
logger = Logger -> IO ()
trace_flush Logger
logger
defaultTraceFlush :: IO ()
defaultTraceFlush :: IO ()
defaultTraceFlush = Handle -> IO ()
hFlush Handle
stderr
initLogger :: IO Logger
initLogger :: IO Logger
initLogger = do
DumpCache
dumps <- Map FilePath (MVar ()) -> IO DumpCache
forall a. a -> IO (MVar a)
newMVar Map FilePath (MVar ())
forall k a. Map k a
Map.empty
Logger -> IO Logger
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Logger -> IO Logger) -> Logger -> IO Logger
forall a b. (a -> b) -> a -> b
$ Logger
{ log_hook :: [LogAction -> LogAction]
log_hook = []
, dump_hook :: [DumpAction -> DumpAction]
dump_hook = []
, trace_hook :: forall a. [TraceAction a -> TraceAction a]
trace_hook = []
, generated_dumps :: DumpCache
generated_dumps = DumpCache
dumps
, trace_flush :: IO ()
trace_flush = IO ()
defaultTraceFlush
, logFlags :: LogFlags
logFlags = LogFlags
defaultLogFlags
}
putLogMsg :: Logger -> LogAction
putLogMsg :: Logger -> LogAction
putLogMsg Logger
logger = ((LogAction -> LogAction) -> LogAction -> LogAction)
-> LogAction -> [LogAction -> LogAction] -> LogAction
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (LogAction -> LogAction) -> LogAction -> LogAction
forall a b. (a -> b) -> a -> b
($) LogAction
defaultLogAction (Logger -> [LogAction -> LogAction]
log_hook Logger
logger)
putDumpFile :: Logger -> DumpAction
putDumpFile :: Logger -> DumpAction
putDumpFile Logger
logger =
let
fallback :: LogAction
fallback = Logger -> LogAction
putLogMsg Logger
logger
dumps :: DumpCache
dumps = Logger -> DumpCache
generated_dumps Logger
logger
deflt :: DumpAction
deflt = DumpCache -> LogAction -> DumpAction
defaultDumpAction DumpCache
dumps LogAction
fallback
in ((DumpAction -> DumpAction) -> DumpAction -> DumpAction)
-> DumpAction -> [DumpAction -> DumpAction] -> DumpAction
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (DumpAction -> DumpAction) -> DumpAction -> DumpAction
forall a b. (a -> b) -> a -> b
($) DumpAction
deflt (Logger -> [DumpAction -> DumpAction]
dump_hook Logger
logger)
putTraceMsg :: Logger -> TraceAction a
putTraceMsg :: forall a. Logger -> TraceAction a
putTraceMsg Logger
logger = ((TraceAction a -> TraceAction a)
-> TraceAction a -> TraceAction a)
-> TraceAction a
-> [TraceAction a -> TraceAction a]
-> TraceAction a
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (TraceAction a -> TraceAction a) -> TraceAction a -> TraceAction a
forall a b. (a -> b) -> a -> b
($) TraceAction a
forall a. TraceAction a
defaultTraceAction (Logger -> forall a. [TraceAction a -> TraceAction a]
trace_hook Logger
logger)
pushLogHook :: (LogAction -> LogAction) -> Logger -> Logger
pushLogHook :: (LogAction -> LogAction) -> Logger -> Logger
pushLogHook LogAction -> LogAction
h Logger
logger = Logger
logger { log_hook = h:log_hook logger }
popLogHook :: Logger -> Logger
popLogHook :: Logger -> Logger
popLogHook Logger
logger = case Logger -> [LogAction -> LogAction]
log_hook Logger
logger of
[] -> FilePath -> Logger
forall a. HasCallStack => FilePath -> a
panic FilePath
"popLogHook: empty hook stack"
LogAction -> LogAction
_:[LogAction -> LogAction]
hs -> Logger
logger { log_hook = hs }
pushDumpHook :: (DumpAction -> DumpAction) -> Logger -> Logger
pushDumpHook :: (DumpAction -> DumpAction) -> Logger -> Logger
pushDumpHook DumpAction -> DumpAction
h Logger
logger = Logger
logger { dump_hook = h:dump_hook logger }
popDumpHook :: Logger -> Logger
popDumpHook :: Logger -> Logger
popDumpHook Logger
logger = case Logger -> [DumpAction -> DumpAction]
dump_hook Logger
logger of
[] -> FilePath -> Logger
forall a. HasCallStack => FilePath -> a
panic FilePath
"popDumpHook: empty hook stack"
DumpAction -> DumpAction
_:[DumpAction -> DumpAction]
hs -> Logger
logger { dump_hook = hs }
pushTraceHook :: (forall a. TraceAction a -> TraceAction a) -> Logger -> Logger
pushTraceHook :: (forall a. TraceAction a -> TraceAction a) -> Logger -> Logger
pushTraceHook forall a. TraceAction a -> TraceAction a
h Logger
logger = Logger
logger { trace_hook = h:trace_hook logger }
popTraceHook :: Logger -> Logger
popTraceHook :: Logger -> Logger
popTraceHook Logger
logger = case Logger -> forall a. [TraceAction a -> TraceAction a]
trace_hook Logger
logger of
[] -> FilePath -> Logger
forall a. HasCallStack => FilePath -> a
panic FilePath
"popTraceHook: empty hook stack"
[TraceAction Any -> TraceAction Any]
_ -> Logger
logger { trace_hook = tail (trace_hook logger) }
makeThreadSafe :: Logger -> IO Logger
makeThreadSafe :: Logger -> IO Logger
makeThreadSafe Logger
logger = do
MVar ()
lock <- () -> IO (MVar ())
forall a. a -> IO (MVar a)
newMVar ()
let
with_lock :: forall a. IO a -> IO a
with_lock :: forall a. IO a -> IO a
with_lock IO a
act = MVar () -> (() -> IO a) -> IO a
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar MVar ()
lock (IO a -> () -> IO a
forall a b. a -> b -> a
const IO a
act)
log :: (t -> t -> t -> t -> IO a) -> t -> t -> t -> t -> IO a
log t -> t -> t -> t -> IO a
action t
logflags t
msg_class t
loc t
doc =
IO a -> IO a
forall a. IO a -> IO a
with_lock (t -> t -> t -> t -> IO a
action t
logflags t
msg_class t
loc t
doc)
dmp :: (t -> t -> t -> t -> t -> t -> IO a)
-> t -> t -> t -> t -> t -> t -> IO a
dmp t -> t -> t -> t -> t -> t -> IO a
action t
logflags t
sty t
opts t
str t
fmt t
doc =
IO a -> IO a
forall a. IO a -> IO a
with_lock (t -> t -> t -> t -> t -> t -> IO a
action t
logflags t
sty t
opts t
str t
fmt t
doc)
trc :: forall a. TraceAction a -> TraceAction a
trc :: forall a. TraceAction a -> TraceAction a
trc TraceAction a
action LogFlags
logflags FilePath
str SDoc
doc a
v =
IO a -> a
forall a. IO a -> a
unsafePerformIO (IO a -> IO a
forall a. IO a -> IO a
with_lock (a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> IO a) -> a -> IO a
forall a b. (a -> b) -> a -> b
$! TraceAction a
action LogFlags
logflags FilePath
str SDoc
doc a
v))
Logger -> IO Logger
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Logger -> IO Logger) -> Logger -> IO Logger
forall a b. (a -> b) -> a -> b
$ (LogAction -> LogAction) -> Logger -> Logger
pushLogHook LogAction -> LogAction
forall {t} {t} {t} {t} {a}.
(t -> t -> t -> t -> IO a) -> t -> t -> t -> t -> IO a
log
(Logger -> Logger) -> Logger -> Logger
forall a b. (a -> b) -> a -> b
$ (DumpAction -> DumpAction) -> Logger -> Logger
pushDumpHook DumpAction -> DumpAction
forall {t} {t} {t} {t} {t} {t} {a}.
(t -> t -> t -> t -> t -> t -> IO a)
-> t -> t -> t -> t -> t -> t -> IO a
dmp
(Logger -> Logger) -> Logger -> Logger
forall a b. (a -> b) -> a -> b
$ (forall a. TraceAction a -> TraceAction a) -> Logger -> Logger
pushTraceHook TraceAction a -> TraceAction a
forall a. TraceAction a -> TraceAction a
trc
(Logger -> Logger) -> Logger -> Logger
forall a b. (a -> b) -> a -> b
$ Logger
logger
jsonLogAction :: LogAction
jsonLogAction :: LogAction
jsonLogAction LogFlags
_ (MCDiagnostic Severity
SevIgnore DiagnosticReason
_ Maybe DiagnosticCode
_) SrcSpan
_ SDoc
_ = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
jsonLogAction LogFlags
logflags MessageClass
msg_class SrcSpan
srcSpan SDoc
msg
=
LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPutStrDoc LogFlags
logflags Bool
True Handle
stdout
(PprStyle -> SDoc -> SDoc
withPprStyle PprStyle
PprCode (SDoc
doc SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ FilePath -> SDoc
forall doc. IsLine doc => FilePath -> doc
text FilePath
""))
where
str :: FilePath
str = SDocContext -> SDoc -> FilePath
renderWithContext (LogFlags -> SDocContext
log_default_user_context LogFlags
logflags) SDoc
msg
doc :: SDoc
doc = JsonDoc -> SDoc
renderJSON (JsonDoc -> SDoc) -> JsonDoc -> SDoc
forall a b. (a -> b) -> a -> b
$
[(FilePath, JsonDoc)] -> JsonDoc
JSObject [ ( FilePath
"span", SrcSpan -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json SrcSpan
srcSpan )
, ( FilePath
"doc" , FilePath -> JsonDoc
JSString FilePath
str )
, ( FilePath
"messageClass", MessageClass -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json MessageClass
msg_class )
]
defaultLogAction :: LogAction
defaultLogAction :: LogAction
defaultLogAction LogFlags
logflags MessageClass
msg_class SrcSpan
srcSpan SDoc
msg
| DumpFlag -> LogFlags -> Bool
log_dopt DumpFlag
Opt_D_dump_json LogFlags
logflags = LogAction
jsonLogAction LogFlags
logflags MessageClass
msg_class SrcSpan
srcSpan SDoc
msg
| Bool
otherwise = case MessageClass
msg_class of
MessageClass
MCOutput -> SDoc -> IO ()
printOut SDoc
msg
MessageClass
MCDump -> SDoc -> IO ()
printOut (SDoc
msg SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ SDoc
blankLine)
MessageClass
MCInteractive -> SDoc -> IO ()
putStrSDoc SDoc
msg
MessageClass
MCInfo -> SDoc -> IO ()
printErrs SDoc
msg
MessageClass
MCFatal -> SDoc -> IO ()
printErrs SDoc
msg
MCDiagnostic Severity
SevIgnore DiagnosticReason
_ Maybe DiagnosticCode
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
MCDiagnostic Severity
_sev DiagnosticReason
_rea Maybe DiagnosticCode
_code -> IO ()
printDiagnostics
where
printOut :: SDoc -> IO ()
printOut = LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPrintDoc LogFlags
logflags Bool
False Handle
stdout
printErrs :: SDoc -> IO ()
printErrs = LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPrintDoc LogFlags
logflags Bool
False Handle
stderr
putStrSDoc :: SDoc -> IO ()
putStrSDoc = LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPutStrDoc LogFlags
logflags Bool
False Handle
stdout
message :: SDoc
message = Bool -> MessageClass -> SrcSpan -> SDoc -> SDoc
mkLocMessageWarningGroups (LogFlags -> Bool
log_show_warn_groups LogFlags
logflags) MessageClass
msg_class SrcSpan
srcSpan SDoc
msg
printDiagnostics :: IO ()
printDiagnostics = do
Handle -> Char -> IO ()
hPutChar Handle
stderr Char
'\n'
SDoc
caretDiagnostic <-
if LogFlags -> Bool
log_show_caret LogFlags
logflags
then MessageClass -> SrcSpan -> IO SDoc
getCaretDiagnostic MessageClass
msg_class SrcSpan
srcSpan
else SDoc -> IO SDoc
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure SDoc
forall doc. IsOutput doc => doc
empty
SDoc -> IO ()
printErrs (SDoc -> IO ()) -> SDoc -> IO ()
forall a b. (a -> b) -> a -> b
$ (PprStyle -> SDoc) -> SDoc
getPprStyle ((PprStyle -> SDoc) -> SDoc) -> (PprStyle -> SDoc) -> SDoc
forall a b. (a -> b) -> a -> b
$ \PprStyle
style ->
PprStyle -> SDoc -> SDoc
withPprStyle (Bool -> PprStyle -> PprStyle
setStyleColoured Bool
True PprStyle
style)
(SDoc
message SDoc -> SDoc -> SDoc
$+$ SDoc
caretDiagnostic)
defaultLogActionHPrintDoc :: LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPrintDoc :: LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPrintDoc LogFlags
logflags Bool
asciiSpace Handle
h SDoc
d
= LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPutStrDoc LogFlags
logflags Bool
asciiSpace Handle
h (SDoc
d SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ FilePath -> SDoc
forall doc. IsLine doc => FilePath -> doc
text FilePath
"")
defaultLogActionHPutStrDoc :: LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPutStrDoc :: LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPutStrDoc LogFlags
logflags Bool
asciiSpace Handle
h SDoc
d
= SDocContext -> Mode -> Handle -> SDoc -> IO ()
printSDoc (LogFlags -> SDocContext
log_default_user_context LogFlags
logflags) (Bool -> Mode
Pretty.PageMode Bool
asciiSpace) Handle
h SDoc
d
defaultDumpAction :: DumpCache -> LogAction -> DumpAction
defaultDumpAction :: DumpCache -> LogAction -> DumpAction
defaultDumpAction DumpCache
dumps LogAction
log_action LogFlags
logflags PprStyle
sty DumpFlag
flag FilePath
title DumpFormat
_fmt SDoc
doc =
DumpCache
-> LogAction
-> PprStyle
-> LogFlags
-> DumpFlag
-> FilePath
-> SDoc
-> IO ()
dumpSDocWithStyle DumpCache
dumps LogAction
log_action PprStyle
sty LogFlags
logflags DumpFlag
flag FilePath
title SDoc
doc
dumpSDocWithStyle :: DumpCache -> LogAction -> PprStyle -> LogFlags -> DumpFlag -> String -> SDoc -> IO ()
dumpSDocWithStyle :: DumpCache
-> LogAction
-> PprStyle
-> LogFlags
-> DumpFlag
-> FilePath
-> SDoc
-> IO ()
dumpSDocWithStyle DumpCache
dumps LogAction
log_action PprStyle
sty LogFlags
logflags DumpFlag
flag FilePath
hdr SDoc
doc =
DumpCache
-> LogFlags -> DumpFlag -> (Maybe Handle -> IO ()) -> IO ()
withDumpFileHandle DumpCache
dumps LogFlags
logflags DumpFlag
flag Maybe Handle -> IO ()
writeDump
where
writeDump :: Maybe Handle -> IO ()
writeDump (Just Handle
handle) = do
SDoc
doc' <- if FilePath -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
hdr
then SDoc -> IO SDoc
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return SDoc
doc
else do SDoc
timeStamp <- if LogFlags -> Bool
log_enable_timestamps LogFlags
logflags
then (FilePath -> SDoc
forall doc. IsLine doc => FilePath -> doc
text (FilePath -> SDoc) -> (UTCTime -> FilePath) -> UTCTime -> SDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> FilePath
forall a. Show a => a -> FilePath
show) (UTCTime -> SDoc) -> IO UTCTime -> IO SDoc
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO UTCTime
getCurrentTime
else SDoc -> IO SDoc
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure SDoc
forall doc. IsOutput doc => doc
empty
let d :: SDoc
d = SDoc
timeStamp
SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ SDoc
blankLine
SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$ SDoc
doc
SDoc -> IO SDoc
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (SDoc -> IO SDoc) -> SDoc -> IO SDoc
forall a b. (a -> b) -> a -> b
$ FilePath -> SDoc -> SDoc
mkDumpDoc FilePath
hdr SDoc
d
LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPrintDoc LogFlags
logflags Bool
True Handle
handle (PprStyle -> SDoc -> SDoc
withPprStyle PprStyle
sty SDoc
doc')
writeDump Maybe Handle
Nothing = do
let (SDoc
doc', MessageClass
msg_class)
| FilePath -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
hdr = (SDoc
doc, MessageClass
MCOutput)
| Bool
otherwise = (FilePath -> SDoc -> SDoc
mkDumpDoc FilePath
hdr SDoc
doc, MessageClass
MCDump)
LogAction
log_action LogFlags
logflags MessageClass
msg_class SrcSpan
noSrcSpan (PprStyle -> SDoc -> SDoc
withPprStyle PprStyle
sty SDoc
doc')
withDumpFileHandle :: DumpCache -> LogFlags -> DumpFlag -> (Maybe Handle -> IO ()) -> IO ()
withDumpFileHandle :: DumpCache
-> LogFlags -> DumpFlag -> (Maybe Handle -> IO ()) -> IO ()
withDumpFileHandle DumpCache
dumps LogFlags
logflags DumpFlag
flag Maybe Handle -> IO ()
action = do
let dump_ways :: Maybe Ways
dump_ways = LogFlags -> Maybe Ways
log_ways LogFlags
logflags
let mFile :: Maybe FilePath
mFile = LogFlags -> Maybe Ways -> DumpFlag -> Maybe FilePath
chooseDumpFile LogFlags
logflags Maybe Ways
dump_ways DumpFlag
flag
case Maybe FilePath
mFile of
Just FilePath
fileName -> do
MVar ()
lock <- DumpCache
-> (Map FilePath (MVar ()) -> IO (Map FilePath (MVar ()), MVar ()))
-> IO (MVar ())
forall a b. MVar a -> (a -> IO (a, b)) -> IO b
modifyMVar DumpCache
dumps ((Map FilePath (MVar ()) -> IO (Map FilePath (MVar ()), MVar ()))
-> IO (MVar ()))
-> (Map FilePath (MVar ()) -> IO (Map FilePath (MVar ()), MVar ()))
-> IO (MVar ())
forall a b. (a -> b) -> a -> b
$ \Map FilePath (MVar ())
gd ->
case FilePath -> Map FilePath (MVar ()) -> Maybe (MVar ())
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
fileName Map FilePath (MVar ())
gd of
Maybe (MVar ())
Nothing -> do
MVar ()
lock <- () -> IO (MVar ())
forall a. a -> IO (MVar a)
newMVar ()
let gd' :: Map FilePath (MVar ())
gd' = FilePath
-> MVar () -> Map FilePath (MVar ()) -> Map FilePath (MVar ())
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert FilePath
fileName MVar ()
lock Map FilePath (MVar ())
gd
Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (ShowS
takeDirectory FilePath
fileName)
FilePath -> FilePath -> IO ()
writeFile FilePath
fileName FilePath
""
(Map FilePath (MVar ()), MVar ())
-> IO (Map FilePath (MVar ()), MVar ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Map FilePath (MVar ())
gd', MVar ()
lock)
Just MVar ()
lock -> do
(Map FilePath (MVar ()), MVar ())
-> IO (Map FilePath (MVar ()), MVar ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Map FilePath (MVar ())
gd, MVar ()
lock)
let withLock :: IO () -> IO ()
withLock IO ()
k = MVar () -> (() -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar MVar ()
lock ((() -> IO ()) -> IO ()) -> (() -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \() -> IO ()
k IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
IO () -> IO ()
withLock (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
withFile FilePath
fileName IOMode
AppendMode ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Handle
handle -> do
Handle -> TextEncoding -> IO ()
hSetEncoding Handle
handle TextEncoding
utf8
Maybe Handle -> IO ()
action (Handle -> Maybe Handle
forall a. a -> Maybe a
Just Handle
handle)
Maybe FilePath
Nothing -> Maybe Handle -> IO ()
action Maybe Handle
forall a. Maybe a
Nothing
chooseDumpFile :: LogFlags -> Maybe Ways -> DumpFlag -> Maybe FilePath
chooseDumpFile :: LogFlags -> Maybe Ways -> DumpFlag -> Maybe FilePath
chooseDumpFile LogFlags
logflags Maybe Ways
ways DumpFlag
flag
| LogFlags -> Bool
log_dump_to_file LogFlags
logflags Bool -> Bool -> Bool
|| Bool
forced_to_file
= FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just (FilePath -> Maybe FilePath) -> FilePath -> Maybe FilePath
forall a b. (a -> b) -> a -> b
$ ShowS
setDir (FilePath
getPrefix FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
way_infix FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
dump_suffix)
| Bool
otherwise
= Maybe FilePath
forall a. Maybe a
Nothing
where
way_infix :: FilePath
way_infix = case Maybe Ways
ways of
Maybe Ways
_ | Bool -> Bool
not (LogFlags -> Bool
log_with_ways LogFlags
logflags) -> FilePath
""
Maybe Ways
Nothing -> FilePath
""
Just Ways
ws
| Ways -> Bool
forall a. Set a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Ways
ws Bool -> Bool -> Bool
|| FilePath -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Ways -> FilePath
waysTag Ways
ws) -> FilePath
""
| Bool
otherwise -> Ways -> FilePath
waysTag Ways
ws FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
"."
(Bool
forced_to_file, FilePath
dump_suffix) = case DumpFlag
flag of
DumpFlag
Opt_D_th_dec_file -> (Bool
True, FilePath
"th.hs")
DumpFlag
_ -> (Bool
False, FilePath
default_suffix)
default_suffix :: FilePath
default_suffix = (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map (\Char
c -> if Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'_' then Char
'-' else Char
c) ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
let str :: FilePath
str = DumpFlag -> FilePath
forall a. Show a => a -> FilePath
show DumpFlag
flag
in case FilePath -> FilePath -> Maybe FilePath
forall a. Eq a => [a] -> [a] -> Maybe [a]
stripPrefix FilePath
"Opt_D_" FilePath
str of
Just FilePath
x -> FilePath
x
Maybe FilePath
Nothing -> ShowS
forall a. HasCallStack => FilePath -> a
panic (FilePath
"chooseDumpFile: bad flag name: " FilePath -> ShowS
forall a. [a] -> [a] -> [a]
++ FilePath
str)
getPrefix :: FilePath
getPrefix
| Just FilePath
prefix <- LogFlags -> Maybe FilePath
log_dump_prefix_override LogFlags
logflags
= FilePath
prefix
| Bool
otherwise
= LogFlags -> FilePath
log_dump_prefix LogFlags
logflags
setDir :: ShowS
setDir FilePath
f = case LogFlags -> Maybe FilePath
log_dump_dir LogFlags
logflags of
Just FilePath
d -> FilePath
d FilePath -> ShowS
</> FilePath
f
Maybe FilePath
Nothing -> FilePath
f
defaultTraceAction :: TraceAction a
defaultTraceAction :: forall a. TraceAction a
defaultTraceAction LogFlags
logflags FilePath
title SDoc
doc a
x =
if Bool -> Bool
not (LogFlags -> Bool
log_enable_debug LogFlags
logflags)
then a
x
else FilePath -> a -> a
forall a. FilePath -> a -> a
trace (SDocContext -> SDoc -> FilePath
renderWithContext (LogFlags -> SDocContext
log_default_dump_context LogFlags
logflags)
([SDoc] -> SDoc
forall doc. IsLine doc => [doc] -> doc
sep [FilePath -> SDoc
forall doc. IsLine doc => FilePath -> doc
text FilePath
title, Int -> SDoc -> SDoc
nest Int
2 SDoc
doc])) a
x
logMsg :: Logger -> MessageClass -> SrcSpan -> SDoc -> IO ()
logMsg :: Logger -> MessageClass -> SrcSpan -> SDoc -> IO ()
logMsg Logger
logger MessageClass
mc SrcSpan
loc SDoc
msg = Logger -> LogAction
putLogMsg Logger
logger (Logger -> LogFlags
logFlags Logger
logger) MessageClass
mc SrcSpan
loc SDoc
msg
logDumpFile :: Logger -> PprStyle -> DumpFlag -> String -> DumpFormat -> SDoc -> IO ()
logDumpFile :: Logger
-> PprStyle -> DumpFlag -> FilePath -> DumpFormat -> SDoc -> IO ()
logDumpFile Logger
logger = Logger -> DumpAction
putDumpFile Logger
logger (Logger -> LogFlags
logFlags Logger
logger)
logTraceMsg :: Logger -> String -> SDoc -> a -> a
logTraceMsg :: forall a. Logger -> FilePath -> SDoc -> a -> a
logTraceMsg Logger
logger FilePath
hdr SDoc
doc a
a = Logger -> TraceAction a
forall a. Logger -> TraceAction a
putTraceMsg Logger
logger (Logger -> LogFlags
logFlags Logger
logger) FilePath
hdr SDoc
doc a
a
logDumpMsg :: Logger -> String -> SDoc -> IO ()
logDumpMsg :: Logger -> FilePath -> SDoc -> IO ()
logDumpMsg Logger
logger FilePath
hdr SDoc
doc = Logger -> MessageClass -> SrcSpan -> SDoc -> IO ()
logMsg Logger
logger MessageClass
MCDump SrcSpan
noSrcSpan
(PprStyle -> SDoc -> SDoc
withPprStyle PprStyle
defaultDumpStyle
(FilePath -> SDoc -> SDoc
mkDumpDoc FilePath
hdr SDoc
doc))
mkDumpDoc :: String -> SDoc -> SDoc
mkDumpDoc :: FilePath -> SDoc -> SDoc
mkDumpDoc FilePath
hdr SDoc
doc
= [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat [SDoc
blankLine,
SDoc
line SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> FilePath -> SDoc
forall doc. IsLine doc => FilePath -> doc
text FilePath
hdr SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> SDoc
line,
SDoc
doc,
SDoc
blankLine]
where
line :: SDoc
line = FilePath -> SDoc
forall doc. IsLine doc => FilePath -> doc
text FilePath
"===================="
putDumpFileMaybe :: Logger -> DumpFlag -> String -> DumpFormat -> SDoc -> IO ()
putDumpFileMaybe :: Logger -> DumpFlag -> FilePath -> DumpFormat -> SDoc -> IO ()
putDumpFileMaybe Logger
logger = Logger
-> NamePprCtx
-> DumpFlag
-> FilePath
-> DumpFormat
-> SDoc
-> IO ()
putDumpFileMaybe' Logger
logger NamePprCtx
alwaysQualify
{-# INLINE putDumpFileMaybe #-}
putDumpFileMaybe'
:: Logger
-> NamePprCtx
-> DumpFlag
-> String
-> DumpFormat
-> SDoc
-> IO ()
putDumpFileMaybe' :: Logger
-> NamePprCtx
-> DumpFlag
-> FilePath
-> DumpFormat
-> SDoc
-> IO ()
putDumpFileMaybe' Logger
logger NamePprCtx
name_ppr_ctx DumpFlag
flag FilePath
hdr DumpFormat
fmt SDoc
doc
= Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Logger -> DumpFlag -> Bool
logHasDumpFlag Logger
logger DumpFlag
flag) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
Logger
-> NamePprCtx
-> DumpFlag
-> FilePath
-> DumpFormat
-> SDoc
-> IO ()
logDumpFile' Logger
logger NamePprCtx
name_ppr_ctx DumpFlag
flag FilePath
hdr DumpFormat
fmt SDoc
doc
{-# INLINE putDumpFileMaybe' #-}
logDumpFile' :: Logger -> NamePprCtx -> DumpFlag
-> String -> DumpFormat -> SDoc -> IO ()
{-# NOINLINE logDumpFile' #-}
logDumpFile' :: Logger
-> NamePprCtx
-> DumpFlag
-> FilePath
-> DumpFormat
-> SDoc
-> IO ()
logDumpFile' Logger
logger NamePprCtx
name_ppr_ctx DumpFlag
flag FilePath
hdr DumpFormat
fmt SDoc
doc
= Logger
-> PprStyle -> DumpFlag -> FilePath -> DumpFormat -> SDoc -> IO ()
logDumpFile Logger
logger (NamePprCtx -> PprStyle
mkDumpStyle NamePprCtx
name_ppr_ctx) DumpFlag
flag FilePath
hdr DumpFormat
fmt SDoc
doc
touchDumpFile :: Logger -> DumpFlag -> IO ()
touchDumpFile :: Logger -> DumpFlag -> IO ()
touchDumpFile Logger
logger DumpFlag
flag =
DumpCache
-> LogFlags -> DumpFlag -> (Maybe Handle -> IO ()) -> IO ()
withDumpFileHandle (Logger -> DumpCache
generated_dumps Logger
logger) (Logger -> LogFlags
logFlags Logger
logger) DumpFlag
flag (IO () -> Maybe Handle -> IO ()
forall a b. a -> b -> a
const (() -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()))
class HasLogger m where
getLogger :: m Logger
class ContainsLogger t where
:: t -> Logger