{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
module Control.Distributed.Process.Debug
(
TraceArg(..)
, TraceFlags(..)
, TraceSubject(..)
, enableTrace
, enableTraceAsync
, disableTrace
, withTracer
, withFlags
, getTraceFlags
, setTraceFlags
, setTraceFlagsAsync
, defaultTraceFlags
, traceOn
, traceOnly
, traceOff
, startTracer
, stopTracer
, traceLog
, traceLogFmt
, traceMessage
, Remote.remoteTable
, Remote.startTraceRelay
, Remote.setTraceFlagsRemote
, systemLoggerTracer
, logfileTracer
, eventLogTracer
)
where
import Control.Applicative
import Control.Distributed.Process.Internal.Primitives
( proxy
, die
, whereis
, send
, receiveWait
, matchIf
, monitor
)
import Control.Distributed.Process.Internal.Types
( ProcessId
, Process
, LocalProcess(..)
, ProcessMonitorNotification(..)
)
import Control.Distributed.Process.Management.Internal.Types
( MxEvent(..)
)
import Control.Distributed.Process.Management.Internal.Trace.Types
( TraceArg(..)
, TraceFlags(..)
, TraceSubject(..)
, defaultTraceFlags
)
import Control.Distributed.Process.Management.Internal.Trace.Tracer
( systemLoggerTracer
, logfileTracer
, eventLogTracer
)
import Control.Distributed.Process.Management.Internal.Trace.Primitives
( withRegisteredTracer
, enableTrace
, enableTraceAsync
, disableTrace
, setTraceFlags
, setTraceFlagsAsync
, getTraceFlags
, traceOn
, traceOff
, traceOnly
, traceLog
, traceLogFmt
, traceMessage
)
import qualified Control.Distributed.Process.Management.Internal.Trace.Remote as Remote
import Control.Distributed.Process.Node
import Control.Exception (SomeException)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Reader (ask)
import Control.Monad.Catch (finally, try)
import Data.Binary()
import Prelude
startTracer :: (MxEvent -> Process ()) -> Process ProcessId
startTracer :: (MxEvent -> Process ()) -> Process ProcessId
startTracer MxEvent -> Process ()
handler = do
(ProcessId -> Process ProcessId) -> Process ProcessId
forall a. (ProcessId -> Process a) -> Process a
withRegisteredTracer ((ProcessId -> Process ProcessId) -> Process ProcessId)
-> (ProcessId -> Process ProcessId) -> Process ProcessId
forall a b. (a -> b) -> a -> b
$ \ProcessId
pid -> 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
ProcessId
newPid <- IO ProcessId -> Process ProcessId
forall a. IO a -> Process a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ProcessId -> Process ProcessId)
-> IO ProcessId -> Process ProcessId
forall a b. (a -> b) -> a -> b
$ LocalNode -> Process () -> IO ProcessId
forkProcess LocalNode
node (Process () -> IO ProcessId) -> Process () -> IO ProcessId
forall a b. (a -> b) -> a -> b
$ ProcessId -> (MxEvent -> Process ()) -> Process ()
traceProxy ProcessId
pid MxEvent -> Process ()
handler
ProcessId -> Process ()
enableTrace ProcessId
newPid
ProcessId -> Process ProcessId
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ProcessId
newPid
withTracer :: forall a.
(MxEvent -> Process ())
-> Process a
-> Process (Either SomeException a)
withTracer :: forall a.
(MxEvent -> Process ())
-> Process a -> Process (Either SomeException a)
withTracer MxEvent -> Process ()
handler Process a
proc = do
Maybe ProcessId
previous <- String -> Process (Maybe ProcessId)
whereis String
"tracer"
ProcessId
tracer <- (MxEvent -> Process ()) -> Process ProcessId
startTracer MxEvent -> Process ()
handler
Process (Either SomeException a)
-> Process () -> Process (Either SomeException a)
forall (m :: * -> *) a b.
(HasCallStack, MonadMask m) =>
m a -> m b -> m a
finally (Process a -> Process (Either SomeException a)
forall (m :: * -> *) e a.
(HasCallStack, MonadCatch m, Exception e) =>
m a -> m (Either e a)
try Process a
proc)
(ProcessId -> Maybe ProcessId -> Process ()
stopTracing ProcessId
tracer Maybe ProcessId
previous)
where
stopTracing :: ProcessId -> Maybe ProcessId -> Process ()
stopTracing :: ProcessId -> Maybe ProcessId -> Process ()
stopTracing ProcessId
tracer Maybe ProcessId
previousTracer = do
case Maybe ProcessId
previousTracer of
Maybe ProcessId
Nothing -> () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just ProcessId
_ -> do
MonitorRef
ref <- ProcessId -> Process MonitorRef
monitor ProcessId
tracer
ProcessId -> MxEvent -> Process ()
forall a. Serializable a => ProcessId -> a -> Process ()
send ProcessId
tracer MxEvent
MxTraceDisable
[Match ()] -> Process ()
forall b. [Match b] -> Process b
receiveWait [
(ProcessMonitorNotification -> Bool)
-> (ProcessMonitorNotification -> Process ()) -> Match ()
forall a b.
Serializable a =>
(a -> Bool) -> (a -> Process b) -> Match b
matchIf (\(ProcessMonitorNotification MonitorRef
ref' ProcessId
_ DiedReason
_) -> MonitorRef
ref MonitorRef -> MonitorRef -> Bool
forall a. Eq a => a -> a -> Bool
== MonitorRef
ref')
(\ProcessMonitorNotification
_ -> () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
]
withFlags :: forall a.
TraceFlags
-> Process a
-> Process (Either SomeException a)
withFlags :: forall a.
TraceFlags -> Process a -> Process (Either SomeException a)
withFlags TraceFlags
flags Process a
proc = do
TraceFlags
oldFlags <- Process TraceFlags
getTraceFlags
Process (Either SomeException a)
-> Process () -> Process (Either SomeException a)
forall (m :: * -> *) a b.
(HasCallStack, MonadMask m) =>
m a -> m b -> m a
finally (TraceFlags -> Process ()
setTraceFlags TraceFlags
flags Process ()
-> Process (Either SomeException a)
-> Process (Either SomeException a)
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Process a -> Process (Either SomeException a)
forall (m :: * -> *) e a.
(HasCallStack, MonadCatch m, Exception e) =>
m a -> m (Either e a)
try Process a
proc)
(TraceFlags -> Process ()
setTraceFlags TraceFlags
oldFlags)
traceProxy :: ProcessId -> (MxEvent -> Process ()) -> Process ()
traceProxy :: ProcessId -> (MxEvent -> Process ()) -> Process ()
traceProxy ProcessId
pid MxEvent -> Process ()
act = do
ProcessId -> (MxEvent -> Process Bool) -> Process ()
forall a.
Serializable a =>
ProcessId -> (a -> Process Bool) -> Process ()
proxy ProcessId
pid ((MxEvent -> Process Bool) -> Process ())
-> (MxEvent -> Process Bool) -> Process ()
forall a b. (a -> b) -> a -> b
$ \(MxEvent
ev :: MxEvent) ->
case MxEvent
ev of
(MxTraceTakeover ProcessId
_) -> Bool -> Process Bool
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
MxEvent
MxTraceDisable -> String -> Process Bool
forall a b. Serializable a => a -> Process b
die String
"disabled"
MxEvent
_ -> MxEvent -> Process ()
act MxEvent
ev Process () -> Process Bool -> Process Bool
forall a b. Process a -> Process b -> Process b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> Process Bool
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
stopTracer :: Process ()
stopTracer :: Process ()
stopTracer =
(ProcessId -> Process ()) -> Process ()
forall a. (ProcessId -> Process a) -> Process a
withRegisteredTracer ((ProcessId -> Process ()) -> Process ())
-> (ProcessId -> Process ()) -> Process ()
forall a b. (a -> b) -> a -> b
$ \ProcessId
pid -> do
Maybe ProcessId
basePid <- String -> Process (Maybe ProcessId)
whereis String
"tracer.initial"
case Maybe ProcessId
basePid Maybe ProcessId -> Maybe ProcessId -> Bool
forall a. Eq a => a -> a -> Bool
== (ProcessId -> Maybe ProcessId
forall a. a -> Maybe a
Just ProcessId
pid) of
Bool
True -> () -> Process ()
forall a. a -> Process a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Bool
False -> ProcessId -> MxEvent -> Process ()
forall a. Serializable a => ProcessId -> a -> Process ()
send ProcessId
pid MxEvent
MxTraceDisable