module GHC.Utils.Logger
( Logger
, HasLogger (..)
, ContainsLogger (..)
, initLogger
, LogAction
, LogJsonAction
, DumpAction
, TraceAction
, DumpFormat (..)
, popLogHook
, pushLogHook
, popJsonLogHook
, pushJsonLogHook
, popDumpHook
, pushDumpHook
, popTraceHook
, pushTraceHook
, makeThreadSafe
, LogFlags (..)
, defaultLogFlags
, log_dopt
, log_set_dopt
, setLogFlags
, updateLogFlags
, logFlags
, logHasDumpFlag
, logVerbAtLeast
, putLogMsg
, defaultLogAction
, defaultLogActionWithHandles
, defaultLogJsonAction
, defaultLogActionHPrintDoc
, defaultLogActionHPutStrDoc
, logMsg
, logJsonMsg
, logDumpMsg
, decorateDiagnostic
, defaultDumpAction
, putDumpFile
, putDumpFileMaybe
, putDumpFileMaybe'
, withDumpFileHandle
, touchDumpFile
, logDumpFile
, defaultTraceAction
, putTraceMsg
, loggerTraceFlushUpdate
, loggerTraceFlush
, logTraceMsg
)
where
import GHC.Prelude
import GHC.Driver.Flags
import GHC.Types.Error
( MessageClass (..), Severity (..)
, mkLocMessageWarningGroups,getCaretDiagnostic )
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 GHC.Data.FastString
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_diagnostics_as_json :: !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 {k} (a :: k). EnumSet a
EnumSet.empty
, log_show_caret :: Bool
log_show_caret = Bool
True
, log_diagnostics_as_json :: Bool
log_diagnostics_as_json = Bool
False
, 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 LogJsonAction = LogFlags
-> MessageClass
-> JsonDoc
-> 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 -> [LogJsonAction -> LogJsonAction]
json_log_hook :: [LogJsonAction -> LogJsonAction]
, 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
dumps <- Map FilePath (MVar ()) -> IO DumpCache
forall a. a -> IO (MVar a)
newMVar Map FilePath (MVar ())
forall k a. Map k a
Map.empty
return $ Logger
{ log_hook = []
, json_log_hook = []
, dump_hook = []
, trace_hook = []
, generated_dumps = dumps
, trace_flush = defaultTraceFlush
, 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)
putJsonLogMsg :: Logger -> LogJsonAction
putJsonLogMsg :: Logger -> LogJsonAction
putJsonLogMsg Logger
logger = ((LogJsonAction -> LogJsonAction)
-> LogJsonAction -> LogJsonAction)
-> LogJsonAction
-> [LogJsonAction -> LogJsonAction]
-> LogJsonAction
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (LogJsonAction -> LogJsonAction) -> LogJsonAction -> LogJsonAction
forall a b. (a -> b) -> a -> b
($) LogJsonAction
defaultLogJsonAction (Logger -> [LogJsonAction -> LogJsonAction]
json_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 }
pushJsonLogHook :: (LogJsonAction -> LogJsonAction) -> Logger -> Logger
pushJsonLogHook :: (LogJsonAction -> LogJsonAction) -> Logger -> Logger
pushJsonLogHook LogJsonAction -> LogJsonAction
h Logger
logger = Logger
logger { json_log_hook = h:json_log_hook logger }
popJsonLogHook :: Logger -> Logger
popJsonLogHook :: Logger -> Logger
popJsonLogHook Logger
logger = case Logger -> [LogJsonAction -> LogJsonAction]
json_log_hook Logger
logger of
[] -> FilePath -> Logger
forall a. HasCallStack => FilePath -> a
panic FilePath
"popJsonLogHook: empty hook stack"
LogJsonAction -> LogJsonAction
_:[LogJsonAction -> LogJsonAction]
hs -> Logger
logger { json_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 a_0 -> TraceAction a_0]
_ -> Logger
logger { trace_hook = tail (trace_hook logger) }
makeThreadSafe :: Logger -> IO Logger
makeThreadSafe :: Logger -> IO Logger
makeThreadSafe Logger
logger = do
lock <- () -> IO (MVar ())
forall a. a -> IO (MVar a)
newMVar ()
let
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
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
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 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))
return $ pushLogHook log
$ pushDumpHook dmp
$ pushTraceHook trc
$ logger
defaultLogJsonAction :: LogJsonAction
defaultLogJsonAction :: LogJsonAction
defaultLogJsonAction LogFlags
logflags MessageClass
msg_class JsonDoc
jsdoc =
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 ResolvedDiagnosticReason
_ Maybe DiagnosticCode
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
MCDiagnostic Severity
_sev ResolvedDiagnosticReason
_rea Maybe DiagnosticCode
_code -> SDoc -> IO ()
printErrs SDoc
msg
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
msg :: SDoc
msg = JsonDoc -> SDoc
renderJSON JsonDoc
jsdoc
jsonLogActionWithHandle :: Handle -> LogAction
jsonLogActionWithHandle :: Handle -> LogAction
jsonLogActionWithHandle Handle
_ LogFlags
_ (MCDiagnostic Severity
SevIgnore ResolvedDiagnosticReason
_ Maybe DiagnosticCode
_) SrcSpan
_ SDoc
_ = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
jsonLogActionWithHandle Handle
out LogFlags
logflags MessageClass
msg_class SrcSpan
srcSpan SDoc
msg
=
LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPutStrDoc LogFlags
logflags Bool
True Handle
out
(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
spanToDumpJSON SrcSpan
srcSpan )
, ( FilePath
"doc" , FilePath -> JsonDoc
JSString FilePath
str )
, ( FilePath
"messageClass", MessageClass -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json MessageClass
msg_class )
]
spanToDumpJSON :: SrcSpan -> JsonDoc
spanToDumpJSON :: SrcSpan -> JsonDoc
spanToDumpJSON SrcSpan
s = case SrcSpan
s of
(RealSrcSpan RealSrcSpan
rss Maybe BufSpan
_) -> [(FilePath, JsonDoc)] -> JsonDoc
JSObject [ (FilePath
"file", FilePath -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json FilePath
file)
, (FilePath
"startLine", Int -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json (Int -> JsonDoc) -> Int -> JsonDoc
forall a b. (a -> b) -> a -> b
$ RealSrcSpan -> Int
srcSpanStartLine RealSrcSpan
rss)
, (FilePath
"startCol", Int -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json (Int -> JsonDoc) -> Int -> JsonDoc
forall a b. (a -> b) -> a -> b
$ RealSrcSpan -> Int
srcSpanStartCol RealSrcSpan
rss)
, (FilePath
"endLine", Int -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json (Int -> JsonDoc) -> Int -> JsonDoc
forall a b. (a -> b) -> a -> b
$ RealSrcSpan -> Int
srcSpanEndLine RealSrcSpan
rss)
, (FilePath
"endCol", Int -> JsonDoc
forall a. ToJson a => a -> JsonDoc
json (Int -> JsonDoc) -> Int -> JsonDoc
forall a b. (a -> b) -> a -> b
$ RealSrcSpan -> Int
srcSpanEndCol RealSrcSpan
rss)
]
where file :: FilePath
file = FastString -> FilePath
unpackFS (FastString -> FilePath) -> FastString -> FilePath
forall a b. (a -> b) -> a -> b
$ RealSrcSpan -> FastString
srcSpanFile RealSrcSpan
rss
GeneratedSrcSpan{} -> JsonDoc
JSNull
UnhelpfulSpan{} -> JsonDoc
JSNull
defaultLogAction :: LogAction
defaultLogAction :: LogAction
defaultLogAction = Handle -> Handle -> LogAction
defaultLogActionWithHandles Handle
stdout Handle
stderr
defaultLogActionWithHandles :: Handle  -> Handle -> LogAction
defaultLogActionWithHandles :: Handle -> Handle -> LogAction
defaultLogActionWithHandles Handle
out Handle
err LogFlags
logflags MessageClass
msg_class SrcSpan
srcSpan SDoc
msg
| DumpFlag -> LogFlags -> Bool
log_dopt DumpFlag
Opt_D_dump_json LogFlags
logflags = Handle -> LogAction
jsonLogActionWithHandle Handle
out 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 ResolvedDiagnosticReason
_ Maybe DiagnosticCode
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
MCDiagnostic Severity
_sev ResolvedDiagnosticReason
_rea Maybe DiagnosticCode
_code -> LogFlags -> MessageClass -> SrcSpan -> SDoc -> IO SDoc
decorateDiagnostic LogFlags
logflags MessageClass
msg_class SrcSpan
srcSpan SDoc
msg IO SDoc -> (SDoc -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= SDoc -> IO ()
printErrs
where
printOut :: SDoc -> IO ()
printOut = LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPrintDoc LogFlags
logflags Bool
False Handle
out
printErrs :: SDoc -> IO ()
printErrs = LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPrintDoc LogFlags
logflags Bool
False Handle
err
putStrSDoc :: SDoc -> IO ()
putStrSDoc = LogFlags -> Bool -> Handle -> SDoc -> IO ()
defaultLogActionHPutStrDoc LogFlags
logflags Bool
False Handle
out
decorateDiagnostic :: LogFlags -> MessageClass -> SrcSpan -> SDoc -> IO SDoc
decorateDiagnostic :: LogFlags -> MessageClass -> SrcSpan -> SDoc -> IO SDoc
decorateDiagnostic LogFlags
logflags MessageClass
msg_class SrcSpan
srcSpan SDoc
msg = IO SDoc
addCaret
where
message :: SDoc
message :: SDoc
message = Bool -> MessageClass -> SrcSpan -> SDoc -> SDoc
mkLocMessageWarningGroups (LogFlags -> Bool
log_show_warn_groups LogFlags
logflags) MessageClass
msg_class SrcSpan
srcSpan SDoc
msg
addCaret :: IO SDoc
addCaret :: IO SDoc
addCaret = do
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
return $ getPprStyle $ \PprStyle
style ->
PprStyle -> SDoc -> SDoc
withPprStyle (Bool -> PprStyle -> PprStyle
setStyleColoured Bool
True PprStyle
style)
(SDoc
message SDoc -> SDoc -> SDoc
$+$ SDoc
caretDiagnostic SDoc -> SDoc -> SDoc
$+$ SDoc
blankLine)
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
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 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
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
return $ mkDumpDoc hdr d
defaultLogActionHPrintDoc logflags True handle (withPprStyle sty 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
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
lock <- () -> IO (MVar ())
forall a. a -> IO (MVar a)
newMVar ()
let 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
createDirectoryIfMissing True (takeDirectory fileName)
writeFile fileName ""
return (gd', 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 ()
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 ()
withLock $ withFile fileName AppendMode $ \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
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
logJsonMsg :: Logger -> MessageClass -> JsonDoc -> IO ()
logJsonMsg :: Logger -> MessageClass -> JsonDoc -> IO ()
logJsonMsg Logger
logger MessageClass
mc = Logger -> LogJsonAction
putJsonLogMsg Logger
logger (Logger -> LogFlags
logFlags Logger
logger) MessageClass
mc
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