6

I've spawned a Greenlet and linked it to a callable. Some time later, the Greenlet fails with an Exception. The linked callable gets called. That's all great!

Here's the issue:

The traceback for the Exception appears on my console, as you'd expect. But I want do things with that traceback within the linked callable. How do I get access to that traceback within the linked callable?

(My first instinct was to use traceback.extract_stack(), but it turns out that provides a traceback for the linked callable itself and not for the Exception.)

Stephen Diehl
  • 8,271
  • 5
  • 38
  • 56
kkurian
  • 3,844
  • 3
  • 30
  • 49

4 Answers4

17

The traceback is intentionally not saved when the Greenlet dies. If it was saved, it would keep a lot of objects alive that are expected to be deleted, which matters especially if the object manages some resource (open file or socket).

If you want to save the traceback you have to do it yourself.

Denis
  • 3,760
  • 25
  • 22
2

As an alternative to Stephen Diehl's solution using Greenlet.link_exception.

import traceback

import gevent

def job():
    raise Exception('ooops')

def on_exception(greenlet):
    try:
        greenlet.get()
    except Exception:
        err = traceback.format_exc()
        # Do something with `err`

g = gevent.spawn(job)
g.link_exception(on_exception)
Peter Lithammer
  • 317
  • 2
  • 5
  • You would spawn then link rather than create, link, and start? Is there any practical difference? – kkurian Oct 11 '16 at 17:11
  • And does this address the concerns I raised in comments to Diehl's solution? – kkurian Oct 11 '16 at 17:14
  • Well I guess theoretically the greenlet could crash before the link is created this way. – Peter Lithammer Oct 11 '16 at 19:59
  • Did some testing, and it seems like it doesn't really address your concern. However it gets the entire stacktrace, but it will just contain some extra references too (like greenlet.get()). https://github.com/gevent/gevent/pull/589 – Peter Lithammer Oct 11 '16 at 20:00
1

The Greenlet object should have an exception property that you can look at:

http://www.gevent.org/gevent.html#gevent.Greenlet.exception

Amber
  • 507,862
  • 82
  • 626
  • 550
1

Just make sure you grab the exception value of the Greenlet and throw it outside the Greenlet, for example get returns either the value returned or raises the internal exception.

import traceback
import gevent

def fail():
    return 0/0

gl = gevent.spawn(fail)

try:
    gl.get()
except Exception as e:
    stack_trace = traceback.format_exc() # here's your stacktrace

Should give you what you need.

Stephen Diehl
  • 8,271
  • 5
  • 38
  • 56
  • I'm trying to get the traceback within a linked callable (e.g., foo = gevent.Greenlet(x); foo.link_exception(bar); foo.start(); ; ) -- doing what you've suggested within bar() does not produce the traceback for the Exception as it was raised in foo, it produces the traceback for the Exception as it is raised in bar. – kkurian Feb 13 '12 at 22:52
  • Perhaps you should paste your code up above, your issue seems to a scoping problem and it would be easier to debug if we could see how you are setting up your scopes. – Stephen Diehl Feb 14 '12 at 00:01