{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Control.Distributed.Process.Management.Internal.Trace.Tracer
(
traceController
, defaultTracer
, systemLoggerTracer
, logfileTracer
, eventLogTracer
) where
import Control.Applicative
import Control.Concurrent.Chan (writeChan)
import Control.Concurrent.MVar
( MVar
, putMVar
)
import Control.Distributed.Process.Internal.CQueue
( CQueue
)
import Control.Distributed.Process.Internal.Primitives
( die
, receiveWait
, forward
, sendChan
, match
, matchAny
, matchIf
, handleMessage
, matchUnknown
)
import Control.Distributed.Process.Management.Internal.Types
( MxEvent(..)
, Addressable(..)
)
import Control.Distributed.Process.Management.Internal.Trace.Types
( SetTrace(..)
, TraceSubject(..)
, TraceFlags(..)
, TraceOk(..)
, defaultTraceFlags
)
import Control.Distributed.Process.Management.Internal.Trace.Primitives
( traceOn )
import Control.Distributed.Process.Internal.Types
( LocalNode(..)
, NCMsg(..)
, ProcessId
, Process
, LocalProcess(..)
, Identifier(..)
, ProcessSignal(NamedSend)
, Message
, SendPort
, forever'
, nullProcessId
, createUnencodedMessage
)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Reader (ask)
import Control.Monad.Catch
( catch
, finally
)
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
import Data.Time.Clock (getCurrentTime)
import Data.Time.Format (formatTime)
import Debug.Trace (traceEventIO)
import Prelude
import System.Environment (getEnv)
import System.IO
( Handle
, IOMode(AppendMode)
, BufferMode(..)
, openFile
, hClose
, hPutStrLn
, hSetBuffering
)
import Data.Time.Format (defaultTimeLocale)
import System.Mem.Weak
( Weak
)
data TracerState =
TracerST
{
TracerState -> Maybe ProcessId
client :: !(Maybe ProcessId)
, TracerState -> TraceFlags
flags :: !TraceFlags
, TracerState -> Map ProcessId (Set String)
regNames :: !(Map ProcessId (Set String))
}
defaultTracer :: Process ()
defaultTracer :: Process ()
defaultTracer =
Process () -> (IOError -> Process ()) -> Process ()
forall e a.
(HasCallStack, Exception e) =>
Process a -> (e -> Process a) -> Process a
forall (m :: * -> *) e a.
(MonadCatch m, HasCallStack, Exception e) =>
m a -> (e -> m a) -> m a
catch (String -> Process String
checkEnv String
"DISTRIBUTED_PROCESS_TRACE_FILE" Process String -> (String -> Process ()) -> Process ()
forall a b. Process a -> (a -> Process b) -> Process b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> Process ()
logfileTracer)
(\(IOError
_ :: IOError) -> Process ()
defaultTracerAux)
defaultTracerAux :: Process ()
defaultTracerAux :: Process ()
defaultTracerAux =
Process () -> (IOError -> Process ()) -> Process ()
forall e a.
(HasCallStack, Exception e) =>
Process a -> (e -> Process a) -> Process a
forall (m :: * -> *) e a.
(MonadCatch m, HasCallStack, Exception e) =>
m a -> (e -> m a) -> m a
catch (String -> Process String
checkEnv String
"DISTRIBUTED_PROCESS_TRACE_CONSOLE" Process String -> Process () -> Process ()
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Process ()
systemLoggerTracer)
(\(IOError
_ :: IOError) -> Process ()
defaultEventLogTracer)
defaultEventLogTracer :: Process ()
defaultEventLogTracer :: Process ()
defaultEventLogTracer =
Process () -> (IOError -> Process ()) -> Process ()
forall e a.
(HasCallStack, Exception e) =>
Process a -> (e -> Process a) -> Process a
forall (m :: * -> *) e a.
(MonadCatch m, HasCallStack, Exception e) =>
m a -> (e -> m a) -> m a
catch (String -> Process String
checkEnv String
"DISTRIBUTED_PROCESS_TRACE_EVENTLOG" Process String -> Process () -> Process ()
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Process ()
eventLogTracer)
(\(IOError
_ :: IOError) -> Process ()
nullTracer)
checkEnv :: String -> Process String
checkEnv :: String -> Process String
checkEnv String
s = IO String -> Process String
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO String -> Process String) -> IO String -> Process String
forall a b. (a -> b) -> a -> b
$ String -> IO String
getEnv String
s
nullTracer :: Process ()
nullTracer :: Process ()
nullTracer =
Process () -> Process ()
forall (m :: * -> *) a b. Monad m => m a -> m b
forever' (Process () -> Process ()) -> Process () -> Process ()
forall a b. (a -> b) -> a -> b
$ [Match ()] -> Process ()
forall b. [Match b] -> Process b
receiveWait [ Process () -> Match ()
forall b. Process b -> Match b
matchUnknown (() -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ]
systemLoggerTracer :: Process ()
systemLoggerTracer :: Process ()
systemLoggerTracer = do
LocalNode
node <- LocalProcess -> LocalNode
processNode (LocalProcess -> LocalNode)
-> Process LocalProcess -> Process LocalNode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Process LocalProcess
forall r (m :: * -> *). MonadReader r m => m r
ask
let tr :: MxEvent -> Process ()
tr = LocalNode -> MxEvent -> Process ()
sendTraceLog LocalNode
node
Process (Maybe ()) -> Process ()
forall (m :: * -> *) a b. Monad m => m a -> m b
forever' (Process (Maybe ()) -> Process ())
-> Process (Maybe ()) -> Process ()
forall a b. (a -> b) -> a -> b
$ [Match (Maybe ())] -> Process (Maybe ())
forall b. [Match b] -> Process b
receiveWait [ (Message -> Process (Maybe ())) -> Match (Maybe ())
forall b. (Message -> Process b) -> Match b
matchAny (\Message
m -> Message -> (MxEvent -> Process ()) -> Process (Maybe ())
forall (m :: * -> *) a b.
(Monad m, Serializable a) =>
Message -> (a -> m b) -> m (Maybe b)
handleMessage Message
m MxEvent -> Process ()
tr) ]
where
sendTraceLog :: LocalNode -> MxEvent -> Process ()
sendTraceLog :: LocalNode -> MxEvent -> Process ()
sendTraceLog LocalNode
node MxEvent
ev = do
UTCTime
now <- IO UTCTime -> Process UTCTime
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO UTCTime -> Process UTCTime) -> IO UTCTime -> Process UTCTime
forall a b. (a -> b) -> a -> b
$ IO UTCTime
getCurrentTime
(String, String)
msg <- (String, String) -> Process (String, String)
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ((String, String) -> Process (String, String))
-> (String, String) -> Process (String, String)
forall a b. (a -> b) -> a -> b
$ (TimeLocale -> String -> UTCTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%c" UTCTime
now, MxEvent -> String
buildTxt MxEvent
ev)
ProcessId
emptyPid <- ProcessId -> Process ProcessId
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return (ProcessId -> Process ProcessId) -> ProcessId -> Process ProcessId
forall a b. (a -> b) -> a -> b
$ (NodeId -> ProcessId
nullProcessId (LocalNode -> NodeId
localNodeId LocalNode
node))
NCMsg
traceMsg <- NCMsg -> Process NCMsg
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return (NCMsg -> Process NCMsg) -> NCMsg -> Process NCMsg
forall a b. (a -> b) -> a -> b
$ NCMsg {
ctrlMsgSender :: Identifier
ctrlMsgSender = ProcessId -> Identifier
ProcessIdentifier (ProcessId
emptyPid)
, ctrlMsgSignal :: ProcessSignal
ctrlMsgSignal = (String -> Message -> ProcessSignal
NamedSend String
"trace.logger"
((String, String) -> Message
forall a. Serializable a => a -> Message
createUnencodedMessage (String, String)
msg))
}
IO () -> Process ()
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> IO () -> Process ()
forall a b. (a -> b) -> a -> b
$ Chan NCMsg -> NCMsg -> IO ()
forall a. Chan a -> a -> IO ()
writeChan (LocalNode -> Chan NCMsg
localCtrlChan LocalNode
node) NCMsg
traceMsg
buildTxt :: MxEvent -> String
buildTxt :: MxEvent -> String
buildTxt (MxLog String
msg) = String
msg
buildTxt MxEvent
ev = MxEvent -> String
forall a. Show a => a -> String
show MxEvent
ev
eventLogTracer :: Process ()
eventLogTracer :: Process ()
eventLogTracer =
Process (Maybe ()) -> Process ()
forall (m :: * -> *) a b. Monad m => m a -> m b
forever' (Process (Maybe ()) -> Process ())
-> Process (Maybe ()) -> Process ()
forall a b. (a -> b) -> a -> b
$ [Match (Maybe ())] -> Process (Maybe ())
forall b. [Match b] -> Process b
receiveWait [ (Message -> Process (Maybe ())) -> Match (Maybe ())
forall b. (Message -> Process b) -> Match b
matchAny (\Message
m -> Message -> (MxEvent -> Process ()) -> Process (Maybe ())
forall (m :: * -> *) a b.
(Monad m, Serializable a) =>
Message -> (a -> m b) -> m (Maybe b)
handleMessage Message
m MxEvent -> Process ()
writeTrace) ]
where
writeTrace :: MxEvent -> Process ()
writeTrace :: MxEvent -> Process ()
writeTrace MxEvent
ev = IO () -> Process ()
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> IO () -> Process ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
traceEventIO (MxEvent -> String
forall a. Show a => a -> String
show MxEvent
ev)
logfileTracer :: FilePath -> Process ()
logfileTracer :: String -> Process ()
logfileTracer String
p = do
Handle
h <- IO Handle -> Process Handle
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Handle -> Process Handle) -> IO Handle -> Process Handle
forall a b. (a -> b) -> a -> b
$ String -> IOMode -> IO Handle
openFile String
p IOMode
AppendMode
IO () -> Process ()
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> IO () -> Process ()
forall a b. (a -> b) -> a -> b
$ Handle -> BufferMode -> IO ()
hSetBuffering Handle
h BufferMode
LineBuffering
Handle -> Process ()
logger Handle
h Process () -> Process () -> Process ()
forall (m :: * -> *) a b.
(HasCallStack, MonadMask m) =>
m a -> m b -> m a
`finally` (IO () -> Process ()
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> IO () -> Process ()
forall a b. (a -> b) -> a -> b
$ Handle -> IO ()
hClose Handle
h)
where
logger :: Handle -> Process ()
logger :: Handle -> Process ()
logger Handle
h' = Process (Maybe ()) -> Process ()
forall (m :: * -> *) a b. Monad m => m a -> m b
forever' (Process (Maybe ()) -> Process ())
-> Process (Maybe ()) -> Process ()
forall a b. (a -> b) -> a -> b
$ do
[Match (Maybe ())] -> Process (Maybe ())
forall b. [Match b] -> Process b
receiveWait [
(MxEvent -> Bool)
-> (MxEvent -> Process (Maybe ())) -> Match (Maybe ())
forall a b.
Serializable a =>
(a -> Bool) -> (a -> Process b) -> Match b
matchIf (\MxEvent
ev -> case MxEvent
ev of
MxEvent
MxTraceDisable -> Bool
True
(MxTraceTakeover ProcessId
_) -> Bool
True
MxEvent
_ -> Bool
False)
(\MxEvent
_ -> (IO () -> Process ()
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> IO () -> Process ()
forall a b. (a -> b) -> a -> b
$ Handle -> IO ()
hClose Handle
h') Process () -> Process (Maybe ()) -> Process (Maybe ())
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> Process (Maybe ())
forall a b. Serializable a => a -> Process b
die String
"trace stopped")
, (Message -> Process (Maybe ())) -> Match (Maybe ())
forall b. (Message -> Process b) -> Match b
matchAny (\Message
ev -> Message -> (MxEvent -> Process ()) -> Process (Maybe ())
forall (m :: * -> *) a b.
(Monad m, Serializable a) =>
Message -> (a -> m b) -> m (Maybe b)
handleMessage Message
ev (Handle -> MxEvent -> Process ()
writeTrace Handle
h'))
]
writeTrace :: Handle -> MxEvent -> Process ()
writeTrace :: Handle -> MxEvent -> Process ()
writeTrace Handle
h MxEvent
ev = do
IO () -> Process ()
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> IO () -> Process ()
forall a b. (a -> b) -> a -> b
$ do
UTCTime
now <- IO UTCTime
getCurrentTime
Handle -> String -> IO ()
hPutStrLn Handle
h (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ (TimeLocale -> String -> UTCTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%c - " UTCTime
now) String -> String -> String
forall a. [a] -> [a] -> [a]
++ (MxEvent -> String
forall a. Show a => a -> String
show MxEvent
ev)
traceController :: MVar ((Weak (CQueue Message))) -> Process ()
traceController :: MVar (Weak (CQueue Message)) -> Process ()
traceController MVar (Weak (CQueue Message))
mv = do
Weak (CQueue Message)
weakQueue <- LocalProcess -> Weak (CQueue Message)
processWeakQ (LocalProcess -> Weak (CQueue Message))
-> Process LocalProcess -> Process (Weak (CQueue Message))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Process LocalProcess
forall r (m :: * -> *). MonadReader r m => m r
ask
IO () -> Process ()
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Process ()) -> IO () -> Process ()
forall a b. (a -> b) -> a -> b
$ MVar (Weak (CQueue Message)) -> Weak (CQueue Message) -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Weak (CQueue Message))
mv Weak (CQueue Message)
weakQueue
TracerState
initState <- Process TracerState
initialState
TracerState -> Process ()
traceLoop TracerState
initState { client = Nothing }
where
traceLoop :: TracerState -> Process ()
traceLoop :: TracerState -> Process ()
traceLoop TracerState
st = do
let client' :: Maybe ProcessId
client' = TracerState -> Maybe ProcessId
client TracerState
st
TracerState
st' <- [Match TracerState] -> Process TracerState
forall b. [Match b] -> Process b
receiveWait [
((Maybe (SendPort TraceOk), SetTrace) -> Process TracerState)
-> Match TracerState
forall a b. Serializable a => (a -> Process b) -> Match b
match (\(Maybe (SendPort TraceOk)
setResp, SetTrace
set :: SetTrace) -> do
case SetTrace
set of
(TraceEnable ProcessId
pid) -> do
Maybe ProcessId -> Message -> Process ()
sendTraceMsg Maybe ProcessId
client' (MxEvent -> Message
forall a. Serializable a => a -> Message
createUnencodedMessage (ProcessId -> MxEvent
MxTraceTakeover ProcessId
pid))
Maybe (SendPort TraceOk) -> Process ()
sendOk Maybe (SendPort TraceOk)
setResp
TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st { client = (Just pid) }
SetTrace
TraceDisable -> do
Maybe ProcessId -> Message -> Process ()
sendTraceMsg Maybe ProcessId
client' (MxEvent -> Message
forall a. Serializable a => a -> Message
createUnencodedMessage MxEvent
MxTraceDisable)
Maybe (SendPort TraceOk) -> Process ()
sendOk Maybe (SendPort TraceOk)
setResp
TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st { client = Nothing })
, ((Maybe (SendPort TraceOk), TraceFlags) -> Process TracerState)
-> Match TracerState
forall a b. Serializable a => (a -> Process b) -> Match b
match (\(Maybe (SendPort TraceOk)
confResp, TraceFlags
flags') ->
Maybe (SendPort TraceOk) -> Process ()
sendOk Maybe (SendPort TraceOk)
confResp Process () -> Process TracerState -> Process TracerState
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TraceFlags -> TracerState -> Process TracerState
applyTraceFlags TraceFlags
flags' TracerState
st)
, (SendPort TraceFlags -> Process TracerState) -> Match TracerState
forall a b. Serializable a => (a -> Process b) -> Match b
match (\SendPort TraceFlags
chGetFlags -> SendPort TraceFlags -> TraceFlags -> Process ()
forall a. Serializable a => SendPort a -> a -> Process ()
sendChan SendPort TraceFlags
chGetFlags (TracerState -> TraceFlags
flags TracerState
st) Process () -> Process TracerState -> Process TracerState
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st)
, (SendPort (Maybe ProcessId) -> Process TracerState)
-> Match TracerState
forall a b. Serializable a => (a -> Process b) -> Match b
match (\SendPort (Maybe ProcessId)
chGetCurrent -> SendPort (Maybe ProcessId) -> Maybe ProcessId -> Process ()
forall a. Serializable a => SendPort a -> a -> Process ()
sendChan SendPort (Maybe ProcessId)
chGetCurrent (TracerState -> Maybe ProcessId
client TracerState
st) Process () -> Process TracerState -> Process TracerState
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st)
, (Message -> Process TracerState) -> Match TracerState
forall b. (Message -> Process b) -> Match b
matchAny (\Message
ev ->
Message
-> (MxEvent -> Process TracerState) -> Process (Maybe TracerState)
forall (m :: * -> *) a b.
(Monad m, Serializable a) =>
Message -> (a -> m b) -> m (Maybe b)
handleMessage Message
ev (TracerState -> Message -> MxEvent -> Process TracerState
handleTrace TracerState
st Message
ev) Process (Maybe TracerState)
-> (Maybe TracerState -> Process TracerState)
-> Process TracerState
forall a b. Process a -> (a -> Process b) -> Process b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return (TracerState -> Process TracerState)
-> (Maybe TracerState -> TracerState)
-> Maybe TracerState
-> Process TracerState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TracerState -> Maybe TracerState -> TracerState
forall a. a -> Maybe a -> a
fromMaybe TracerState
st)
]
TracerState -> Process ()
traceLoop TracerState
st'
sendOk :: Maybe (SendPort TraceOk) -> Process ()
sendOk :: Maybe (SendPort TraceOk) -> Process ()
sendOk Maybe (SendPort TraceOk)
Nothing = () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
sendOk (Just SendPort TraceOk
sp) = SendPort TraceOk -> TraceOk -> Process ()
forall a. Serializable a => SendPort a -> a -> Process ()
sendChan SendPort TraceOk
sp TraceOk
TraceOk
initialState :: Process TracerState
initialState :: Process TracerState
initialState = do
TraceFlags
flags' <- Process TraceFlags
checkEnvFlags
TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return (TracerState -> Process TracerState)
-> TracerState -> Process TracerState
forall a b. (a -> b) -> a -> b
$ TracerST { client :: Maybe ProcessId
client = Maybe ProcessId
forall a. Maybe a
Nothing
, flags :: TraceFlags
flags = TraceFlags
flags'
, regNames :: Map ProcessId (Set String)
regNames = Map ProcessId (Set String)
forall k a. Map k a
Map.empty
}
checkEnvFlags :: Process TraceFlags
checkEnvFlags :: Process TraceFlags
checkEnvFlags =
Process TraceFlags
-> (IOError -> Process TraceFlags) -> Process TraceFlags
forall e a.
(HasCallStack, Exception e) =>
Process a -> (e -> Process a) -> Process a
forall (m :: * -> *) e a.
(MonadCatch m, HasCallStack, Exception e) =>
m a -> (e -> m a) -> m a
catch (String -> Process String
checkEnv String
"DISTRIBUTED_PROCESS_TRACE_FLAGS" Process String
-> (String -> Process TraceFlags) -> Process TraceFlags
forall a b. Process a -> (a -> Process b) -> Process b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= TraceFlags -> Process TraceFlags
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return (TraceFlags -> Process TraceFlags)
-> (String -> TraceFlags) -> String -> Process TraceFlags
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> TraceFlags
parseFlags)
(\(IOError
_ :: IOError) -> TraceFlags -> Process TraceFlags
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TraceFlags
defaultTraceFlags)
parseFlags :: String -> TraceFlags
parseFlags :: String -> TraceFlags
parseFlags String
s = String -> TraceFlags -> TraceFlags
parseFlags' String
s TraceFlags
defaultTraceFlags
where parseFlags' :: String -> TraceFlags -> TraceFlags
parseFlags' :: String -> TraceFlags -> TraceFlags
parseFlags' [] TraceFlags
parsedFlags = TraceFlags
parsedFlags
parseFlags' (Char
x:String
xs) TraceFlags
parsedFlags
| Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'p' = String -> TraceFlags -> TraceFlags
parseFlags' String
xs TraceFlags
parsedFlags { traceSpawned = traceOn }
| Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'n' = String -> TraceFlags -> TraceFlags
parseFlags' String
xs TraceFlags
parsedFlags { traceRegistered = traceOn }
| Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'u' = String -> TraceFlags -> TraceFlags
parseFlags' String
xs TraceFlags
parsedFlags { traceUnregistered = traceOn }
| Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'd' = String -> TraceFlags -> TraceFlags
parseFlags' String
xs TraceFlags
parsedFlags { traceDied = traceOn }
| Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
's' = String -> TraceFlags -> TraceFlags
parseFlags' String
xs TraceFlags
parsedFlags { traceSend = traceOn }
| Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'r' = String -> TraceFlags -> TraceFlags
parseFlags' String
xs TraceFlags
parsedFlags { traceRecv = traceOn }
| Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'l' = String -> TraceFlags -> TraceFlags
parseFlags' String
xs TraceFlags
parsedFlags { traceNodes = True }
| Bool
otherwise = String -> TraceFlags -> TraceFlags
parseFlags' String
xs TraceFlags
parsedFlags
applyTraceFlags :: TraceFlags -> TracerState -> Process TracerState
applyTraceFlags :: TraceFlags -> TracerState -> Process TracerState
applyTraceFlags TraceFlags
flags' TracerState
state = TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
state { flags = flags' }
handleTrace :: TracerState -> Message -> MxEvent -> Process TracerState
handleTrace :: TracerState -> Message -> MxEvent -> Process TracerState
handleTrace TracerState
st Message
msg ev :: MxEvent
ev@(MxRegistered ProcessId
p String
n) =
let regNames' :: Map ProcessId (Set String)
regNames' =
(Set String -> Set String -> Set String)
-> ProcessId
-> Set String
-> Map ProcessId (Set String)
-> Map ProcessId (Set String)
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith (\Set String
_ Set String
ns -> String -> Set String -> Set String
forall a. Ord a => a -> Set a -> Set a
Set.insert String
n Set String
ns) ProcessId
p
(String -> Set String
forall a. a -> Set a
Set.singleton String
n)
(TracerState -> Map ProcessId (Set String)
regNames TracerState
st)
in do
MxEvent
-> Message -> Maybe TraceSubject -> TracerState -> Process ()
traceEv MxEvent
ev Message
msg (TraceFlags -> Maybe TraceSubject
traceRegistered (TracerState -> TraceFlags
flags TracerState
st)) TracerState
st
TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st { regNames = regNames' }
handleTrace TracerState
st Message
msg ev :: MxEvent
ev@(MxUnRegistered ProcessId
p String
n) =
let f :: Maybe (Set String) -> Maybe (Set String)
f Maybe (Set String)
ns = case Maybe (Set String)
ns of
Maybe (Set String)
Nothing -> Maybe (Set String)
forall a. Maybe a
Nothing
Just Set String
ns' -> Set String -> Maybe (Set String)
forall a. a -> Maybe a
Just (String -> Set String -> Set String
forall a. Ord a => a -> Set a -> Set a
Set.delete String
n Set String
ns')
regNames' :: Map ProcessId (Set String)
regNames' = (Maybe (Set String) -> Maybe (Set String))
-> ProcessId
-> Map ProcessId (Set String)
-> Map ProcessId (Set String)
forall k a.
Ord k =>
(Maybe a -> Maybe a) -> k -> Map k a -> Map k a
Map.alter Maybe (Set String) -> Maybe (Set String)
f ProcessId
p (TracerState -> Map ProcessId (Set String)
regNames TracerState
st)
in do
MxEvent
-> Message -> Maybe TraceSubject -> TracerState -> Process ()
traceEv MxEvent
ev Message
msg (TraceFlags -> Maybe TraceSubject
traceUnregistered (TracerState -> TraceFlags
flags TracerState
st)) TracerState
st
TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st { regNames = regNames' }
handleTrace TracerState
st Message
msg ev :: MxEvent
ev@(MxSpawned ProcessId
_) = do
MxEvent
-> Message -> Maybe TraceSubject -> TracerState -> Process ()
traceEv MxEvent
ev Message
msg (TraceFlags -> Maybe TraceSubject
traceSpawned (TracerState -> TraceFlags
flags TracerState
st)) TracerState
st Process () -> Process TracerState -> Process TracerState
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st
handleTrace TracerState
st Message
msg ev :: MxEvent
ev@(MxProcessDied ProcessId
_ DiedReason
_) = do
MxEvent
-> Message -> Maybe TraceSubject -> TracerState -> Process ()
traceEv MxEvent
ev Message
msg (TraceFlags -> Maybe TraceSubject
traceDied (TracerState -> TraceFlags
flags TracerState
st)) TracerState
st Process () -> Process TracerState -> Process TracerState
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st
handleTrace TracerState
st Message
msg ev :: MxEvent
ev@(MxSent ProcessId
_ ProcessId
_ Message
_) =
MxEvent
-> Message -> Maybe TraceSubject -> TracerState -> Process ()
traceEv MxEvent
ev Message
msg (TraceFlags -> Maybe TraceSubject
traceSend (TracerState -> TraceFlags
flags TracerState
st)) TracerState
st Process () -> Process TracerState -> Process TracerState
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st
handleTrace TracerState
st Message
msg ev :: MxEvent
ev@(MxReceived ProcessId
_ Message
_) =
MxEvent
-> Message -> Maybe TraceSubject -> TracerState -> Process ()
traceEv MxEvent
ev Message
msg (TraceFlags -> Maybe TraceSubject
traceRecv (TracerState -> TraceFlags
flags TracerState
st)) TracerState
st Process () -> Process TracerState -> Process TracerState
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st
handleTrace TracerState
st Message
msg MxEvent
ev = do
case MxEvent
ev of
(MxNodeDied NodeId
_ DiedReason
_) ->
case (TraceFlags -> Bool
traceNodes (TracerState -> TraceFlags
flags TracerState
st)) of
Bool
True -> TracerState -> MxEvent -> Message -> Process ()
sendTrace TracerState
st MxEvent
ev Message
msg
Bool
False -> () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
(MxUser Message
_) -> TracerState -> MxEvent -> Message -> Process ()
sendTrace TracerState
st MxEvent
ev Message
msg
(MxLog String
_) -> TracerState -> MxEvent -> Message -> Process ()
sendTrace TracerState
st MxEvent
ev Message
msg
MxEvent
_ ->
case (TraceFlags -> Bool
traceConnections (TracerState -> TraceFlags
flags TracerState
st)) of
Bool
True -> TracerState -> MxEvent -> Message -> Process ()
sendTrace TracerState
st MxEvent
ev Message
msg
Bool
False -> () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
TracerState -> Process TracerState
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return TracerState
st
traceEv :: MxEvent
-> Message
-> Maybe TraceSubject
-> TracerState
-> Process ()
traceEv :: MxEvent
-> Message -> Maybe TraceSubject -> TracerState -> Process ()
traceEv MxEvent
_ Message
_ Maybe TraceSubject
Nothing TracerState
_ = () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
traceEv MxEvent
ev Message
msg (Just TraceSubject
TraceAll) TracerState
st = TracerState -> MxEvent -> Message -> Process ()
sendTrace TracerState
st MxEvent
ev Message
msg
traceEv MxEvent
ev Message
msg (Just (TraceProcs Set ProcessId
pids)) TracerState
st = do
LocalNode
node <- LocalProcess -> LocalNode
processNode (LocalProcess -> LocalNode)
-> Process LocalProcess -> Process LocalNode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Process LocalProcess
forall r (m :: * -> *). MonadReader r m => m r
ask
let p :: ProcessId
p = case MxEvent -> Maybe ProcessId
forall a. Addressable a => a -> Maybe ProcessId
resolveToPid MxEvent
ev of
Maybe ProcessId
Nothing -> (NodeId -> ProcessId
nullProcessId (LocalNode -> NodeId
localNodeId LocalNode
node))
Just ProcessId
pid -> ProcessId
pid
case (ProcessId -> Set ProcessId -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.member ProcessId
p Set ProcessId
pids) of
Bool
True -> TracerState -> MxEvent -> Message -> Process ()
sendTrace TracerState
st MxEvent
ev Message
msg
Bool
False -> () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
traceEv MxEvent
ev Message
msg (Just (TraceNames Set String
names)) TracerState
st = do
LocalNode
node <- LocalProcess -> LocalNode
processNode (LocalProcess -> LocalNode)
-> Process LocalProcess -> Process LocalNode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Process LocalProcess
forall r (m :: * -> *). MonadReader r m => m r
ask
let p :: ProcessId
p = case MxEvent -> Maybe ProcessId
forall a. Addressable a => a -> Maybe ProcessId
resolveToPid MxEvent
ev of
Maybe ProcessId
Nothing -> (NodeId -> ProcessId
nullProcessId (LocalNode -> NodeId
localNodeId LocalNode
node))
Just ProcessId
pid -> ProcessId
pid
case (ProcessId -> Map ProcessId (Set String) -> Maybe (Set String)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ProcessId
p (TracerState -> Map ProcessId (Set String)
regNames TracerState
st)) of
Maybe (Set String)
Nothing -> () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just Set String
ns -> if (Set String -> Bool
forall a. Set a -> Bool
Set.null (Set String -> Set String -> Set String
forall a. Ord a => Set a -> Set a -> Set a
Set.intersection Set String
ns Set String
names))
then () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
else TracerState -> MxEvent -> Message -> Process ()
sendTrace TracerState
st MxEvent
ev Message
msg
sendTrace :: TracerState -> MxEvent -> Message -> Process ()
sendTrace :: TracerState -> MxEvent -> Message -> Process ()
sendTrace TracerState
st MxEvent
ev Message
msg = do
let c :: Maybe ProcessId
c = TracerState -> Maybe ProcessId
client TracerState
st
if Maybe ProcessId
c Maybe ProcessId -> Maybe ProcessId -> Bool
forall a. Eq a => a -> a -> Bool
== (MxEvent -> Maybe ProcessId
forall a. Addressable a => a -> Maybe ProcessId
resolveToPid MxEvent
ev)
then () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
else Maybe ProcessId -> Message -> Process ()
sendTraceMsg Maybe ProcessId
c Message
msg
sendTraceMsg :: Maybe ProcessId -> Message -> Process ()
sendTraceMsg :: Maybe ProcessId -> Message -> Process ()
sendTraceMsg Maybe ProcessId
Nothing Message
_ = () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
sendTraceMsg (Just ProcessId
p) Message
msg = ((Message -> ProcessId -> Process ())
-> ProcessId -> Message -> Process ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Message -> ProcessId -> Process ()
forward) ProcessId
p Message
msg