{-# 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