def test_kill_removes_trace(self): from greenlet import gettrace hub = get_hub() hub.start_periodic_monitoring_thread() self.assertIsNotNone(gettrace()) hub.periodic_monitoring_thread.kill() self.assertIsNone(gettrace())
def tearDown(self): monitor.start_new_thread = self._orig_start_new_thread monitor.thread_sleep = self._orig_thread_sleep prev = self.pmt.previous_trace_function self.pmt.kill() assert gettrace() is prev, (gettrace(), prev) settrace(None) super(_AbstractTestPeriodicMonitoringThread, self).tearDown()
def tearDown(self): monitor.start_new_thread = self._orig_start_new_thread monitor.thread_sleep = self._orig_thread_sleep prev = self.pmt._greenlet_tracer.previous_trace_function self.pmt.kill() assert gettrace() is prev, (gettrace(), prev) settrace(None) super(_AbstractTestPeriodicMonitoringThread, self).tearDown()
def test_nested(self): from greenlet import gettrace with util.assert_switches() as outer: self.assertEqual(gettrace(), outer.tracer) self.assertIsNotNone(outer.tracer.active_greenlet) with util.assert_switches() as inner: self.assertEqual(gettrace(), inner.tracer) self.assertEqual(inner.tracer.previous_trace_function, outer.tracer) inner.tracer('switch', (self, self)) self.assertIs(self, inner.tracer.active_greenlet) self.assertIs(self, outer.tracer.active_greenlet) self.assertEqual(gettrace(), outer.tracer)
def test_previous_trace(self): self.pmt.kill() self.assertIsNone(gettrace()) called = [] def f(*args): called.append(args) settrace(f) self.pmt = monitor.PeriodicMonitoringThread(self.hub) self.assertEqual(gettrace(), self.pmt._greenlet_tracer) self.assertIs(self.pmt._greenlet_tracer.previous_trace_function, f) self.pmt._greenlet_tracer('event', ('args',)) self.assertEqual([('event', ('args',))], called)
def test_previous_trace(self): self.pmt.kill() self.assertIsNone(gettrace()) called = [] def f(*args): called.append(args) settrace(f) self.pmt = monitor.PeriodicMonitoringThread(self.hub) self.assertEqual(gettrace(), self.pmt.greenlet_trace) self.assertIs(self.pmt.previous_trace_function, f) self.pmt.greenlet_trace('event', 'args') self.assertEqual([('event', 'args')], called)
def test_hub_wref(self): self.assertIs(self.hub, self.pmt.hub) del self.hub gc.collect() self.assertIsNone(self.pmt.hub) # And it killed itself. self.assertFalse(self.pmt.should_run) self.assertIsNone(gettrace())
def test_b_exception_disables_tracing(self): main = greenlet.getcurrent() def dummy(): main.switch() g = greenlet.greenlet(dummy) g.switch() with GreenletTracer(error_on_trace=True) as actions: self.assertRaises(SomeError, g.switch) self.assertEqual(greenlet.gettrace(), None) self.assertEqual(actions, [ ('switch', (main, g)), ])
def test_exception_disables_tracing(self): main = greenlet.getcurrent() actions = [] def trace(*args): actions.append(args) raise SomeError() def dummy(): main.switch() g = greenlet.greenlet(dummy) g.switch() oldtrace = greenlet.settrace(trace) try: self.assertRaises(SomeError, g.switch) self.assertEqual(greenlet.gettrace(), None) finally: greenlet.settrace(oldtrace) self.assertEqual(actions, [ ('switch', (main, g)), ])
def __init__(self, collector, sample_interval=0.1): self.collector = collector self.sample_interval = sample_interval self.last_timestamp = time.time() # Save the old frame to have proper stack reporting. If the following # code is executed: # # slow() # At this point a new sample is *not* needed # f2() # When this calls happens a new sample is needed, *because # # of the previous function* # # The above gets worse because a context switch can happen after the # call to slow, if this is not taken into account a completely wrong # stack trace will be reported. self.old_frame = None self.previous_callback = greenlet.gettrace() greenlet.settrace(self._greenlet_profiler) # pylint: disable=c-extension-no-member sys.setprofile(self._thread_profiler)
def install_switch_log(): # Do not overwrite the previous installed tracing function, this could be # another profiling tool, and if the callback is overwriten the tool would # not work as expected (e.g. a trace sampler) previous_callback = greenlet.gettrace() def log_every_switch(event: str, args: Any) -> None: if event == "switch": origin, target = args # Collecting the complete stack frame because the top-level # function will be a greenlet, and the bottom function may be an # external library. To understand what is going on the application # code, the whole stack is necessary. frame = sys._getframe(0) callstack = collect_frames(frame) # Using `print` because logging will not work here, the logger may # not be properly initialized on a fresh greenlet and will try to # use a nullable variable. print( json.dumps({ "event": "Switching", "origin": str(origin), "target": str(target), "target_callstack": callstack, "time": datetime.utcnow().isoformat(), })) if previous_callback is not None: return previous_callback(event, args) return None greenlet.settrace(log_every_switch) return previous_callback
def greenlet_settrace(self): 'Check if any greenlet trace function is registered.' return bool(greenlet.gettrace())
def execute(self): self.log.debug('Executing {}'.format(self.graph)) # Initialize graph if self.graph.state == ComponentState.NOT_INITIALIZED: self.graph.initialize() self.graph.state = ComponentState.INITIALIZED # Enable tracing old_trace = greenlet.gettrace() if self.DETECT_BLOCKING: greenlet.settrace(self._blocking_greenlet_detector) self._running = True try: all_components = set() self._graph_lookup = {} for component, graph in self.graph.get_all_components( include_graphs=True): self._graph_lookup[component] = graph all_components.add(component) component.executor = self # Component should always be in a INITIALIZED state when first # running! if component.state != ComponentState.INITIALIZED: raise exc.ComponentStateError( component, 'state is {}, but expected INITIALIZED'.format( component.state)) component.state = ComponentState.ACTIVE self.log.debug('Components in {}: {}'.format( self.graph, ', '.join(map(str, all_components)))) self._recv_queues = collections.defaultdict(queue.Queue) self._coroutines = dict([ ( gevent.spawn( self._create_component_runner(comp), None, # in_queues None), # out_queues comp) for comp in filter( lambda c: not isinstance(c, Graph), all_components) ]) last_exception = None def thread_error_handler(coroutine): """ Handles component coroutine exceptions that get raised. This should terminate execution of all other coroutines. """ last_exception = coroutine.exception component = self._coroutines[coroutine] self.log.error('Component "{}" failed with {}: {}'.format( component.name, coroutine.exception.__class__.__name__, coroutine.exception.message)) for c in all_components: if c.is_alive(): c.terminate(ex=last_exception) # Wire up error handler (so that exceptions aren't swallowed) for coroutine in self._coroutines.keys(): coroutine.link_exception(thread_error_handler) # Wait for all coroutines to terminate gevent.wait(self._coroutines.keys()) self.graph.terminate(ex=last_exception) self._final_checks() self._reset_components() self.log.debug('Finished graph execution') finally: self._running = False if self.DETECT_BLOCKING: # Unset tracer greenlet.settrace(old_trace)
def test_constructor(self): self.assertEqual(0xDEADBEEF, self.pmt.monitor_thread_ident) self.assertEqual(gettrace(), self.pmt._greenlet_tracer)
def execute(self): self.log.debug("Executing {}".format(self.graph)) # Initialize graph if self.graph.state == ComponentState.NOT_INITIALIZED: self.graph.initialize() self.graph.state = ComponentState.INITIALIZED # Enable tracing old_trace = greenlet.gettrace() if self.DETECT_BLOCKING: greenlet.settrace(self._blocking_greenlet_detector) self._running = True try: all_components = set() self._graph_lookup = {} for component, graph in self.graph.get_all_components(include_graphs=True): self._graph_lookup[component] = graph all_components.add(component) component.executor = self # Component should always be in a INITIALIZED state when first # running! if component.state != ComponentState.INITIALIZED: raise exc.ComponentStateError( component, "state is {}, but expected INITIALIZED".format(component.state) ) component.state = ComponentState.ACTIVE self.log.debug("Components in {}: {}".format(self.graph, ", ".join(map(str, all_components)))) self._recv_queues = collections.defaultdict(queue.Queue) self._coroutines = dict( [ (gevent.spawn(self._create_component_runner(comp), None, None), comp) # in_queues # out_queues for comp in filter(lambda c: not isinstance(c, Graph), all_components) ] ) last_exception = None def thread_error_handler(coroutine): """ Handles component coroutine exceptions that get raised. This should terminate execution of all other coroutines. """ last_exception = coroutine.exception component = self._coroutines[coroutine] self.log.error( 'Component "{}" failed with {}: {}'.format( component.name, coroutine.exception.__class__.__name__, coroutine.exception.message ) ) for c in all_components: if c.is_alive(): c.terminate(ex=last_exception) # Wire up error handler (so that exceptions aren't swallowed) for coroutine in self._coroutines.keys(): coroutine.link_exception(thread_error_handler) # Wait for all coroutines to terminate gevent.wait(self._coroutines.keys()) self.graph.terminate(ex=last_exception) self._final_checks() self._reset_components() self.log.debug("Finished graph execution") finally: self._running = False if self.DETECT_BLOCKING: # Unset tracer greenlet.settrace(old_trace)
def test_constructor(self): self.assertEqual(0xDEADBEEF, self.pmt.monitor_thread_ident) self.assertEqual(gettrace(), self.pmt.greenlet_trace)
def _check(): # 任务监控 greenlet.settrace(lambda: 2) greenlet.gettrace()