Add python-eventlet 0.16.1
[packages/trusty/python-eventlet.git] / eventlet / eventlet / debug.py
1 """The debug module contains utilities and functions for better
2 debugging Eventlet-powered applications."""
3 from __future__ import print_function
4
5 import os
6 import sys
7 import linecache
8 import re
9 import inspect
10
11 __all__ = ['spew', 'unspew', 'format_hub_listeners', 'format_hub_timers',
12            'hub_listener_stacks', 'hub_exceptions', 'tpool_exceptions',
13            'hub_prevent_multiple_readers', 'hub_timer_stacks',
14            'hub_blocking_detection']
15
16 _token_splitter = re.compile('\W+')
17
18
19 class Spew(object):
20
21     def __init__(self, trace_names=None, show_values=True):
22         self.trace_names = trace_names
23         self.show_values = show_values
24
25     def __call__(self, frame, event, arg):
26         if event == 'line':
27             lineno = frame.f_lineno
28             if '__file__' in frame.f_globals:
29                 filename = frame.f_globals['__file__']
30                 if (filename.endswith('.pyc') or
31                         filename.endswith('.pyo')):
32                     filename = filename[:-1]
33                 name = frame.f_globals['__name__']
34                 line = linecache.getline(filename, lineno)
35             else:
36                 name = '[unknown]'
37                 try:
38                     src = inspect.getsourcelines(frame)
39                     line = src[lineno]
40                 except IOError:
41                     line = 'Unknown code named [%s].  VM instruction #%d' % (
42                         frame.f_code.co_name, frame.f_lasti)
43             if self.trace_names is None or name in self.trace_names:
44                 print('%s:%s: %s' % (name, lineno, line.rstrip()))
45                 if not self.show_values:
46                     return self
47                 details = []
48                 tokens = _token_splitter.split(line)
49                 for tok in tokens:
50                     if tok in frame.f_globals:
51                         details.append('%s=%r' % (tok, frame.f_globals[tok]))
52                     if tok in frame.f_locals:
53                         details.append('%s=%r' % (tok, frame.f_locals[tok]))
54                 if details:
55                     print("\t%s" % ' '.join(details))
56         return self
57
58
59 def spew(trace_names=None, show_values=False):
60     """Install a trace hook which writes incredibly detailed logs
61     about what code is being executed to stdout.
62     """
63     sys.settrace(Spew(trace_names, show_values))
64
65
66 def unspew():
67     """Remove the trace hook installed by spew.
68     """
69     sys.settrace(None)
70
71
72 def format_hub_listeners():
73     """ Returns a formatted string of the current listeners on the current
74     hub.  This can be useful in determining what's going on in the event system,
75     especially when used in conjunction with :func:`hub_listener_stacks`.
76     """
77     from eventlet import hubs
78     hub = hubs.get_hub()
79     result = ['READERS:']
80     for l in hub.get_readers():
81         result.append(repr(l))
82     result.append('WRITERS:')
83     for l in hub.get_writers():
84         result.append(repr(l))
85     return os.linesep.join(result)
86
87
88 def format_hub_timers():
89     """ Returns a formatted string of the current timers on the current
90     hub.  This can be useful in determining what's going on in the event system,
91     especially when used in conjunction with :func:`hub_timer_stacks`.
92     """
93     from eventlet import hubs
94     hub = hubs.get_hub()
95     result = ['TIMERS:']
96     for l in hub.timers:
97         result.append(repr(l))
98     return os.linesep.join(result)
99
100
101 def hub_listener_stacks(state=False):
102     """Toggles whether or not the hub records the stack when clients register
103     listeners on file descriptors.  This can be useful when trying to figure
104     out what the hub is up to at any given moment.  To inspect the stacks
105     of the current listeners, call :func:`format_hub_listeners` at critical
106     junctures in the application logic.
107     """
108     from eventlet import hubs
109     hubs.get_hub().set_debug_listeners(state)
110
111
112 def hub_timer_stacks(state=False):
113     """Toggles whether or not the hub records the stack when timers are set.
114     To inspect the stacks of the current timers, call :func:`format_hub_timers`
115     at critical junctures in the application logic.
116     """
117     from eventlet.hubs import timer
118     timer._g_debug = state
119
120
121 def hub_prevent_multiple_readers(state=True):
122     """Toggle prevention of multiple greenlets reading from a socket
123
124     When multiple greenlets read from the same socket it is often hard
125     to predict which greenlet will receive what data.  To achieve
126     resource sharing consider using ``eventlet.pools.Pool`` instead.
127
128     But if you really know what you are doing you can change the state
129     to ``False`` to stop the hub from protecting against this mistake.
130     """
131     from eventlet.hubs import hub
132     hub.g_prevent_multiple_readers = state
133
134
135 def hub_exceptions(state=True):
136     """Toggles whether the hub prints exceptions that are raised from its
137     timers.  This can be useful to see how greenthreads are terminating.
138     """
139     from eventlet import hubs
140     hubs.get_hub().set_timer_exceptions(state)
141     from eventlet import greenpool
142     greenpool.DEBUG = state
143
144
145 def tpool_exceptions(state=False):
146     """Toggles whether tpool itself prints exceptions that are raised from
147     functions that are executed in it, in addition to raising them like
148     it normally does."""
149     from eventlet import tpool
150     tpool.QUIET = not state
151
152
153 def hub_blocking_detection(state=False, resolution=1):
154     """Toggles whether Eventlet makes an effort to detect blocking
155     behavior in an application.
156
157     It does this by telling the kernel to raise a SIGALARM after a
158     short timeout, and clearing the timeout every time the hub
159     greenlet is resumed.  Therefore, any code that runs for a long
160     time without yielding to the hub will get interrupted by the
161     blocking detector (don't use it in production!).
162
163     The *resolution* argument governs how long the SIGALARM timeout
164     waits in seconds.  The implementation uses :func:`signal.setitimer`
165     and can be specified as a floating-point value.
166     The shorter the resolution, the greater the chance of false
167     positives.
168     """
169     from eventlet import hubs
170     assert resolution > 0
171     hubs.get_hub().debug_blocking = state
172     hubs.get_hub().debug_blocking_resolution = resolution
173     if not state:
174         hubs.get_hub().block_detect_post()