1-----------------------------------------------------------------------------
3-- Module : Control.Distributed.Process.Debug
4-- Copyright : (c) Well-Typed / Tim Watson
5-- License : BSD3 (see the file LICENSE)
7-- Maintainer : Tim Watson <watson.timothy@gmail.com>
8-- Stability : experimental
9-- Portability : non-portable (requires concurrency)
11-- [Tracing/Debugging Facilities]
13-- Cloud Haskell provides a general purpose tracing mechanism, allowing a
14-- user supplied /tracer process/ to receive messages when certain classes of
15-- system events occur. It's possible to use this facility to aid in debugging
16-- and/or perform other diagnostic tasks to a program at runtime.
20-- Throughout the lifecycle of a local node, the distributed-process runtime
21-- generates /trace events/, describing internal runtime activities such as
22-- the spawning and death of processes, message sending, delivery and so on.
23-- See the 'MxEvent' type's documentation for a list of all the published
24-- event types, which correspond directly to the types of 'Management' event.
25-- Users can additionally publish custom trace events in the form of
26-- 'MxLog' log messages or pass custom (i.e., completely user defined)
27-- event data using the 'traceMessage' function.
29-- All published traces are forwarded to a /tracer process/, which can be
30-- specified (and changed) at runtime using 'traceEnable'. Some pre-defined
31-- tracer processes are provided for conveniently printing to stderr, a log file
32-- or the GHC eventlog.
34-- If a tracer process crashes, no attempt is made to restart it.
36-- [Working with multiple tracer processes]
38-- The tracing facility only ever writes to a single tracer process. This
39-- invariant insulates the tracer controller and ensures a fast path for
40-- handling all trace events. /This/ module provides facilities for layering
41-- trace handlers using Cloud Haskell's built-in delegation primitives.
43-- The 'startTracer' function wraps the registered @tracer@ process with the
44-- supplied handler and also forwards trace events to the original tracer.
45-- The corresponding 'stopTracer' function terminates tracer processes in
46-- reverse of the order in which they were started, and re-registers the
47-- previous tracer process.
51-- The built in tracers provide a simple /logging/ facility that writes trace
52-- events out to either a log file, @stderr@ or the GHC eventlog. These tracers
53-- can be configured using environment variables, or specified manually using
54-- the 'traceEnable' function.
56-- When a new local node is started, the contents of several environment
57-- variables are checked to determine which default tracer process is selected.
58-- If none of these variables is set, a no-op tracer process is installed,
59-- which effectively ignores all trace messages. Note that in this case,
60-- trace events are still generated and passed through the system.
61-- Only one default tracer will be chosen - the first that contains a (valid)
62-- value. These environment variables, in the order they're examined, are:
64-- 1. @DISTRIBUTED_PROCESS_TRACE_FILE@
65-- This is checked for a valid file path. If it exists and the file can be
66-- opened for writing, all trace output will be directed thence. If the supplied
67-- path is invalid, or the file is unavailable for writing, this tracer will not
70-- 2. @DISTRIBUTED_PROCESS_TRACE_CONSOLE@
71-- This is checked for /any/ non-empty value. If set, then all trace output will
72-- be directed to the system logger process.
74-- 3. @DISTRIBUTED_PROCESS_TRACE_EVENTLOG@
75-- This is checked for /any/ non-empty value. If set, all internal traces are
76-- written to the GHC eventlog.
78-- Users of the /simplelocalnet/ Cloud Haskell backend should also note that
79-- because the trace file option only supports trace output from a single node
80-- (so as to avoid interleaving), a file trace configured for the master node
81-- will prevent slaves from tracing to the file. They will need to fall back to
82-- the console or eventlog tracers instead, which can be accomplished by setting
83-- one of these environment variables /as well/, since the latter will only be
84-- selected on slaves (when the file tracer selection fails).
86-- Support for writing to the eventlog requires specific intervention to work,
87-- without which, written traces are silently dropped/ignored and no output will
88-- be generated. The GHC eventlog documentation provides information about
89-- enabling, viewing and working with event traces at
90-- <http://hackage.haskell.org/trac/ghc/wiki/EventLog>.
92module Control.Distributed.Process.Debug
93 ( -- * Exported Data Types
98 -- * Configuring Tracing
114 -- * Sending Custom Trace Data
118 -- * Working with remote nodes
120 , Remote.startTraceRelay
121 , Remote.setTraceFlagsRemote
122 -- * Built in tracers
129import Control.Applicative ((<$>))
130import Control.Distributed.Process.Internal.Primitives
142import Control.Distributed.Process.Internal.Types
146 , ProcessMonitorNotification(..)
148import Control.Distributed.Process.Management.Trace.Types
155import Control.Distributed.Process.Management.Trace.Tracer
160import Control.Distributed.Process.Management.Trace.Primitives
161 ( withRegisteredTracer
175import qualified Control.Distributed.Process.Management.Trace.Remote as Remote
176import Control.Distributed.Process.Node
178import Control.Exception (SomeException)
180import Control.Monad.IO.Class (liftIO)
181import Control.Monad.Reader (ask)
185#if ! MIN_VERSION_base(4,6,0)
186import Prelude hiding (catch)
189--------------------------------------------------------------------------------
190-- Debugging/Tracing API --
191--------------------------------------------------------------------------------
193-- | Starts a new tracer, using the supplied trace function.
194-- Only one tracer can be registered at a time, however /this/ function overlays
195-- the registered tracer with the supplied handler, allowing the user to layer
196-- multiple tracers on top of one another, with trace events forwarded down
197-- through all the layers in turn. Once the top layer is stopped, the user
198-- is responsible for re-registering the original (prior) tracer pid before
199-- terminating. See 'withTracer' for a mechanism that handles that.
200startTracer :: (MxEvent -> Process ()) -> Process ProcessId
201startTracer handler = do
202 withRegisteredTracer $ \pid -> do
203 node <- processNode <$> ask
204 newPid <- liftIO $ forkProcess node $ traceProxy pid handler
205 enableTrace newPid -- invokes sync + registration
208-- | Evaluate @proc@ with tracing enabled via @handler@, and immediately
209-- disable tracing thereafter, before giving the result (or exception
210-- in case of failure).
211withTracer :: forall a.
212 (MxEvent -> Process ())
214 -> Process (Either SomeException a)
215withTracer handler proc = do
216 previous <- whereis "tracer"
217 tracer <- startTracer handler
219 (stopTracing tracer previous)
221 stopTracing :: ProcessId -> Maybe ProcessId -> Process ()
222 stopTracing tracer previousTracer = do
223 case previousTracer of
226 ref <- monitor tracer
227 send tracer MxTraceDisable
229 matchIf (\(ProcessMonitorNotification ref' _ _) -> ref == ref')
233-- | Evaluate @proc@ with the supplied flags enabled. Any previously set
234-- trace flags are restored immediately afterwards.
235withFlags :: forall a.
238 -> Process (Either SomeException a)
239withFlags flags proc = do
240 oldFlags <- getTraceFlags
241 finally (setTraceFlags flags >> try proc)
242 (setTraceFlags oldFlags)
244traceProxy :: ProcessId -> (MxEvent -> Process ()) -> Process ()
245traceProxy pid act = do
246 proxy pid $ \(ev :: MxEvent) ->
248 (MxTraceTakeover _) -> return False
249 MxTraceDisable -> die "disabled"
250 _ -> act ev >> return True
252-- | Stops a user supplied tracer started with 'startTracer'.
253-- Note that only one tracer process can be active at any given time.
254-- This process will stop the last process started with 'startTracer'.
255-- If 'startTracer' is called multiple times, successive calls to this
256-- function will stop the tracers in the reverse order which they were
259-- This function will never stop the system tracer (i.e., the tracer
260-- initially started when the node is created), therefore once all user
261-- supplied tracers (i.e., processes started via 'startTracer') have exited,
262-- subsequent calls to this function will have no effect.
264-- If the last tracer to have been registered was not started
265-- with 'startTracer' then the behaviour of this function is /undefined/.
266stopTracer :: Process ()
268 withRegisteredTracer $ \pid -> do
269 -- we need to avoid killing the initial (base) tracer, as
270 -- nothing we rely on having exactly 1 registered tracer
271 -- process at all times.
272 basePid <- whereis "tracer.initial"
273 case basePid == (Just pid) of
275 False -> send pid MxTraceDisable
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list