@@ -88,9 +88,14 @@ module Control.Distributed.Process.Debug
88 , TraceFlags(..)
88 , TraceFlags(..)
89 , TraceSubject(..)
89 , TraceSubject(..)
90 -- * Configuring Tracing
90 -- * Configuring Tracing
91 , enableTrace
92 , enableTrace
92 , disableTrace
94 , disableTrace
93 , setTraceFlags
97 , setTraceFlags
94 , defaultTraceFlags
99 , defaultTraceFlags
95 -- * Debugging
100 -- * Debugging
96 , startTracer
101 , startTracer
@@ -113,9 +118,16 @@ import Control.Distributed.Process.Internal.Primitives
114 , getSelfPid
119 , getSelfPid
115 , reregister
120 , reregister
117 , whereis
121 , whereis
120import Control.Distributed.Process.Internal.Types
132import Control.Distributed.Process.Internal.Types
121 ( Tracer(..)
133 ( Tracer(..)
@@ -123,12 +135,15 @@ import Control.Distributed.Process.Internal.Types
123 , ProcessId
135 , ProcessId
124 , Process
136 , Process
125 , LocalProcess(..)
137 , LocalProcess(..)
139+ , ProcessMonitorNotification(..)
127import Control.Distributed.Process.Internal.Trace.Types
141import Control.Distributed.Process.Internal.Trace.Types
128 ( TraceArg(..)
142 ( TraceArg(..)
129 , TraceEvent(..)
143 , TraceEvent(..)
130 , TraceFlags(..)
144 , TraceFlags(..)
131 , TraceSubject(..)
145 , TraceSubject(..)
132 , defaultTraceFlags
147 , defaultTraceFlags
134import Control.Distributed.Process.Internal.Trace.Tracer
149import Control.Distributed.Process.Internal.Trace.Tracer
@@ -141,17 +156,27 @@ import qualified Control.Distributed.Process.Internal.Trace.Primitives as Tracer
141 , traceLogFmt
156 , traceLogFmt
142 , traceMessage
157 , traceMessage
143 , enableTrace
158 , enableTrace
144 , disableTrace
160 , disableTrace
145 , setTraceFlags
162 , setTraceFlags
147import Control.Distributed.Process.Node
165import Control.Distributed.Process.Node
148import Control.Distributed.Process.Serializable
166import Control.Distributed.Process.Serializable
168+import Control.Exception (SomeException)
150import Control.Monad.IO.Class (liftIO)
170import Control.Monad.IO.Class (liftIO)
151import Control.Monad.Reader (ask)
171import Control.Monad.Reader (ask)
153import Data.Binary()
173import Data.Binary()
175+#if ! MIN_VERSION_base(4,6,0)
176+import Prelude hiding (catch)
155--------------------------------------------------------------------------------
180--------------------------------------------------------------------------------
156-- Debugging/Tracing API --
181-- Debugging/Tracing API --
157--------------------------------------------------------------------------------
182--------------------------------------------------------------------------------
@@ -161,24 +186,56 @@ import Data.Binary()
161-- the registered tracer with the supplied handler, allowing the user to layer
186-- the registered tracer with the supplied handler, allowing the user to layer
162-- multiple tracers on top of one another, with trace events forwarded down
187-- multiple tracers on top of one another, with trace events forwarded down
163-- through all the layers in turn. Once the top layer is stopped, it will
188-- through all the layers in turn. Once the top layer is stopped, it will
164−-- reregister the original tracer pid before terminating. If no tracer is
189+-- reregister the original (prior) tracer pid before terminating.
165−-- currently registered, this function will have no effect.
166−startTracer :: (TraceEvent -> Process ()) -> Process ()
190+startTracer :: (TraceEvent -> Process ()) -> Process ProcessId
191+startTracer handler = do
167−startTracer handler = withRegisteredTracer $ \pid -> do
193+ withRegisteredTracer $ \pid -> do
168− node <- processNode <$> ask
194+ node <- processNode <$> ask
169− newPid <- liftIO $ forkProcess node $ do
195+ newPid <- liftIO $ forkProcess node $ do
196+ -- TODO: we ensure that the original
197+ -- tracer is re-registered, but it is
198+ -- possible this could lead to races
199+ -- if multiple tracers crash in very
200+ -- close succession, due to scheduling
170− finally (mkProxy pid handler)
201+ finally (traceProxy pid handler)
171− (reregister "tracer" pid)
202+ (resetTracer pid)
172− enableTrace newPid
203+ enableTrace newPid
207+-- | Evaluate @proc@ with tracing enabled via @handler@, and immediately
208+-- disable tracing thereafter, before giving the result (or exception
209+-- in case of failure).
210+withTracer :: forall a.
211+ (TraceEvent -> Process ())
213+ -> Process (Either SomeException a)
214+withTracer handler proc = do
215+ tracer <- startTracer handler
217+ (stopTracing tracer)
219+ stopTracing :: ProcessId -> Process ()
220+ stopTracing tracer = do
221+ ref <- monitor tracer
224+ matchIf (\(ProcessMonitorNotification ref' _ _) -> ref == ref')
174− mkProxy :: ProcessId -> (TraceEvent -> Process ()) -> Process ()
228+traceProxy :: ProcessId -> (TraceEvent -> Process ()) -> Process ()
175− mkProxy pid act = do
229+traceProxy pid act = do
176− getSelfPid >>= register "tracer"
230+ getSelfPid >>= reregister "tracer" -- registration is synchronous
177− proxy pid $ \(ev :: TraceEvent) ->
231+ proxy pid $ \(ev :: TraceEvent) ->
178− case ev of
232+ case ev of
179− (TraceEvTakeover _) -> die "finished"
233+ (TraceEvTakeover _) -> die "takeover"
180− TraceEvDisable -> die "stop"
234+ TraceEvDisable -> die "disabled"
181− _ -> act ev >> return True
235+ _ -> act ev >> return True
237+resetTracer :: ProcessId -> Process ()
238+resetTracer pid = enableTrace pid
183-- | Stops a user supplied tracer started with 'startTracer'.
240-- | Stops a user supplied tracer started with 'startTracer'.
184-- Note that only one tracer process can be active at any given time.
241-- Note that only one tracer process can be active at any given time.
@@ -190,7 +247,7 @@ startTracer handler = withRegisteredTracer $ \pid -> do
190-- This function will never stop the system tracer (i.e., the tracer
247-- This function will never stop the system tracer (i.e., the tracer
191-- initially started when the node is created), therefore once all user
248-- initially started when the node is created), therefore once all user
192-- supplied tracers (i.e., processes started via 'startTracer') have exited,
249-- supplied tracers (i.e., processes started via 'startTracer') have exited,
193−-- subsequent calls to this function have no effect.
250+-- subsequent calls to this function will have no effect.
195-- If tracing is support disabled for the node, this function will also
252-- If tracing is support disabled for the node, this function will also
196-- have no effect.
253-- have no effect.
@@ -209,22 +266,57 @@ stopTracer = withLocalTracer $ \t ->
210withRegisteredTracer :: (ProcessId -> Process ()) -> Process ()
267withRegisteredTracer :: (ProcessId -> Process ()) -> Process ()
211withRegisteredTracer act = do
268withRegisteredTracer act = do
212− t <- whereis "tracer"
269+ currentTracer <- whereis "tracer"
213− case t of
270+ case currentTracer of
214− Nothing -> return ()
271+ Nothing -> do { (Just p') <- whereis "tracer.initial"; act p' }
215− Just pid -> act pid
272+ (Just p) -> act p
274+-- | Determine whether or not tracing has been enabled.
275+isTracingEnabled :: Process Bool
276+isTracingEnabled = do
277+ node <- processNode <$> ask
278+ case (localTracer node) of
279+ (ActiveTracer _ _) -> return True
217-- | Enable tracing to the supplied process.
282-- | Enable tracing to the supplied process.
283+enableTraceAsync :: ProcessId -> Process ()
284+enableTraceAsync pid = withLocalTracer $ \t -> liftIO $ Tracer.enableTrace t pid
286+-- TODO: refactor _Sync versions of trace configuration functions...
288+-- | Enable tracing to the supplied process and wait for a @TraceOk@
289+-- response from the trace coordinator process.
218enableTrace :: ProcessId -> Process ()
290enableTrace :: ProcessId -> Process ()
219−enableTrace pid = withLocalTracer $ \t -> liftIO $ Tracer.enableTrace t pid
291+enableTrace pid =
292+ withLocalTracerSync $ \t sp -> Tracer.enableTraceSync t sp pid
221-- | Disable the currently configured trace.
294-- | Disable the currently configured trace.
295+disableTraceAsync :: Process ()
296+disableTraceAsync = withLocalTracer $ \t -> liftIO $ Tracer.disableTrace t
298+-- | Disable the currently configured trace and wait for a @TraceOk@
299+-- response from the trace coordinator process.
222disableTrace :: Process ()
300disableTrace :: Process ()
223−disableTrace = withLocalTracer $ \t -> liftIO $ Tracer.disableTrace t
301+disableTrace =
302+ withLocalTracerSync $ \t sp -> Tracer.disableTraceSync t sp
225-- | Set the given flags for the current tracer.
304-- | Set the given flags for the current tracer.
305+setTraceFlagsAsync :: TraceFlags -> Process ()
306+setTraceFlagsAsync f = withLocalTracer $ \t -> liftIO $ Tracer.setTraceFlags t f
308+-- | Set the given flags for the current tracer and wait for a @TraceOk@
309+-- response from the trace coordinator process.
226setTraceFlags :: TraceFlags -> Process ()
310setTraceFlags :: TraceFlags -> Process ()
312+ withLocalTracerSync $ \t sp -> Tracer.setTraceFlagsSync t sp f
314+withLocalTracerSync :: (Tracer -> SendPort TraceOk -> IO ()) -> Process ()
315+withLocalTracerSync act = do
227−setTraceFlags f = withLocalTracer $ \t -> liftIO $ Tracer.setTraceFlags t f
317+ withLocalTracer $ \t -> liftIO $ (act t sp)
318+ TraceOk <- receiveChan rp
229-- | Send a log message to the internal tracing facility. If tracing is
321-- | Send a log message to the internal tracing facility. If tracing is
230-- enabled, this will create a custom trace log event.
322-- enabled, this will create a custom trace log event.
@@ -246,3 +338,4 @@ withLocalTracer :: (Tracer -> Process ()) -> Process ()
246withLocalTracer act = do
338withLocalTracer act = do
247 node <- processNode <$> ask
339 node <- processNode <$> ask
248 act (localTracer node)
340 act (localTracer node)