graph-trace-0.1.0.1: src/Graph/Trace/Internal/Types.hs
{-# LANGUAGE DeriveLift #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ImplicitParams #-}
module Graph.Trace.Internal.Types
( DebugTag(..)
, DebugContext(..)
, Propagation(..)
, SrcCodeLoc(..)
, DefinitionSite
, CallSite
, DebugIP
, TraceMute
, TraceDeep
, TraceDeepKey
, Trace
, TraceKey
, TraceInert
, Event(..)
, eventToLogStr
, FunName
, UserKey
, SrcModule
, SrcLine
, SrcCol
, callStackToCallSite
, DebugNames(..)
) where
import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Builder as BSB
import GHC.Stack
import GHC.TypeLits
import qualified Language.Haskell.TH.Syntax as TH
import qualified Graph.Trace.Internal.GhcFacade as Ghc
data Propagation
= Mute -- ^ Does not output traces, overrides other options
| Inert -- ^ Does not output traces, doesn't override other options
| Shallow -- ^ Outputs traces for current scope, but does not propagate
| Deep -- ^ Outputs traces and propagates to descendents
deriving (Eq, Show, TH.Lift)
data DebugContext =
DC { previousTag :: !(Maybe DebugTag)
, currentTag :: {-# UNPACK #-} !DebugTag
, propagation :: !Propagation
, definitionSite :: !(Maybe DefinitionSite)
}
data SrcCodeLoc =
SrcCodeLoc
{ srcModule :: !SrcModule
, srcLine :: !SrcLine
, srcCol :: !SrcCol
} deriving TH.Lift
type SrcModule = String
type SrcLine = Int
type SrcCol = Int
type DefinitionSite = SrcCodeLoc
type CallSite = SrcCodeLoc
type DebugIP = (?_debug_ip :: Maybe DebugContext, HasCallStack)
type TraceMute = DebugIP
type TraceDeep = DebugIP
type TraceDeepKey (key :: Symbol) = DebugIP
type Trace = DebugIP
type TraceKey (key :: Symbol) = DebugIP
type TraceInert = DebugIP
-- These are String because they need to be lifted into TH expressions
type FunName = String
type UserKey = String
type MessageContent = BSL.ByteString
data DebugTag =
DT { invocationId :: {-# UNPACK #-} !Word -- a unique identifier for a particular invocation of a function
, debugKey :: Either FunName UserKey
-- The name of the function containing the current execution context
}
data Event
= EntryEvent
!DebugTag -- ^ Current context
!(Maybe DebugTag) -- ^ caller's context
!(Maybe DefinitionSite)
!(Maybe CallSite)
| TraceEvent
!DebugTag
!MessageContent
!(Maybe CallSite)
callStackToCallSite :: CallStack -> Maybe CallSite
callStackToCallSite cs =
case getCallStack cs of
(_, srcLoc) : _ ->
Just SrcCodeLoc
{ srcModule = srcLocFile srcLoc
, srcLine = srcLocStartLine srcLoc
, srcCol = srcLocStartCol srcLoc
}
_ -> Nothing
sep :: BSB.Builder
sep = BSB.char8 '§'
-- | Serialize an Event. The § character is used as both a separator and
-- terminator. Don't use this character in trace messages, it will break!
eventToLogStr :: Event -> BSB.Builder
eventToLogStr (EntryEvent current mPrevious mDefSite mCallSite)
= BSB.stringUtf8 "entry" <> sep
<> keyStr current <> sep
<> BSB.wordDec (invocationId current) <> sep
<> foldMap keyStr mPrevious <> sep
<> foldMap (BSB.wordDec . invocationId) mPrevious <> sep
<> srcCodeLocToLogStr mDefSite <> sep
<> srcCodeLocToLogStr mCallSite <> sep
eventToLogStr (TraceEvent current message mCallSite)
= BSB.stringUtf8 "trace" <> sep
<> keyStr current <> sep
<> BSB.wordDec (invocationId current) <> sep
<> BSB.lazyByteString message <> sep
<> srcCodeLocToLogStr mCallSite <> sep
srcCodeLocToLogStr :: Maybe SrcCodeLoc -> BSB.Builder
srcCodeLocToLogStr mLoc
= foldMap (BSB.stringUtf8 . srcModule) mLoc <> sep
<> foldMap (BSB.intDec . srcLine) mLoc <> sep
<> foldMap (BSB.intDec . srcCol) mLoc
keyStr :: DebugTag -> BSB.Builder
keyStr
= BSB.stringUtf8
. either
id
id
. debugKey
data DebugNames =
DebugNames
{ traceMutePredName :: Ghc.Name
, traceDeepPredName :: Ghc.Name
, traceDeepKeyPredName :: Ghc.Name
, tracePredName :: Ghc.Name
, traceKeyPredName :: Ghc.Name
, traceInertPredName :: Ghc.Name
, entryName :: Ghc.Name
, debugContextName :: Ghc.Name
}