Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exceptions raised by threads printed to stdout #55

Closed
denik opened this issue Sep 13, 2012 · 7 comments
Closed

Exceptions raised by threads printed to stdout #55

denik opened this issue Sep 13, 2012 · 7 comments
Labels
Status: wontfix Too expensive or difficult to fix

Comments

@denik
Copy link
Member

denik commented Sep 13, 2012

When a thread (eg, one created by gevent.spawn) raises an exception, an error is printed to stderr.

For example:

>>> import gevent
>>> def raise_error():
... raise Exception("oh no!")
>>> thread = gevent.spawn(raise_error)
>>> try: thread.get()
... except: pass
Traceback (most recent call last): # <<< error printed by gevent
...
Exception: oh no!
<Greenlet at 0x1022198d0: raise_error> failed with Exception

>>>

This is not always desirable (eg, in the case of expected exceptions) and can be confusing.
Reported by wolever.

Earlier Comments

Denis.Bilenko said, at 2010-10-29T04:13:44.000Z

This is by design.

There are many ways to send logs to wherever you want:

  • catch the exceptions and log them yourself with try/except
  • subclass Greenlet (complex)
  • replace sys.stderr with your own object
  • redirect stderr to another process which does the logging (trivial)
    "python mygeventapp.py 2>&1 | /usr/bin/logger -t mygeventapp" will log to syslog

In case of expected exceptions it's better to catch them. That way it will be obvious when reading the code that those exceptions are desirable.

wolever said, at 2010-10-29T04:27:41.000Z:

I agree that it's important to be able to log exceptions (especially in the context of threads which would otherwise disappear without a trace), but it would be nice to have some sort of defined interface for controlling where they go.

Additionally, it should be possible to ignore "expected" exceptions entirely so they don't add noise to the log.

If it would be considered useful, I'd be happy to bang together something simple. Say:

  • A defined interface for "where exceptions get logged"
  • Adding a flag to "join" which says "don't worry, I'm aware this might raise an exception"
  • Ignoring (ie, not logging) exceptions raised as a result of a call to ".get()", as they will be re-raised anyway

Denis.Bilenko said, at 2010-10-29T05:03:26.000Z:

Additionally, it should be possible to ignore "expected" exceptions entirely so they don't add noise to the log.

There is already a way to do it: wrap you code with try/except return the exceptions you don't consider errors. There's even a helper function for that: http://gevent.org/gevent.util.html#gevent.util.wrap_errors

A defined interface for "where exceptions get logged

I don't think it's needed, but if stderr is not good for your needs, then consider subclassing Greenlet and rewriting the parts that write to stderr. Keep in mind then gevent writes to stderr in several places so rather than subclass them all it's better to handle stderr somehow (either redirect or monkey patch).

Adding a flag to "join" which says "don't worry, I'm aware this might raise an exception

join() is not the right place for this. Consider what will happen if the greenlet finishes before a call to join() is made.

Ignoring (ie, not logging) exceptions raised as a result of a call to ".get()", as they will be re-raised anyway

This would means there's a chance that the error is lost, because get() might be never called. The current system is dumb on purpose: there must be absolutely no chance that a greenlet dying of error goes unnoticed.

@denik denik closed this as completed Sep 13, 2012
@davedash
Copy link

Couldn't this be logged instead? This is causing a problem in our test suite where we intentionally kill gevent threads.

@olliewalsh
Copy link

For reference, to silence this in gevent 1.0.1:

import gevent.hub
gevent.hub.Hub.NOT_ERROR=(Exception,)

@foxbunny
Copy link

@olliewalsh Does this have any side-effects? Like exception no longer being treated as such in some parts of gevent?

@novocaine
Copy link

There should be some way to silence this. I want to rely on the gevent behaviour of re-raising exceptions upon .get(), which is elegant, and I don't see why my stderr should be spammed during regular handling because of my choice to use this mechanism which is supposed to be supported.

The alternative is awkward: wrap the greenlet body in a try/catch and pass the exception back as the result, inventing a protocol for separating error results from real results along the way.

Couldn't this be a property of the greenlet set during spawn?

@jamadden
Copy link
Member

If you're absolutely sure that none of the points Denis made above about the current strategy will ever apply to your application, in addition to his suggestions, you could set the hub's handle_error property to a function that does something different. (It is called in the hub so it cannot use any blocking functions---logging may use blocking functions in a monkey-patched system.) That's pretty invasive though.

@jamadden jamadden added the Status: wontfix Too expensive or difficult to fix label Nov 16, 2015
@novocaine
Copy link

I'm not sure about the application in general (it's very large), I really just want to alter the default behaviour for this particular greenlet which I use as a very conventional worker thread. The ergonomics are not great here.

@jamadden
Copy link
Member

Then as Denis suggested in the original post, if you don't want to catch-and-return (e.g., wrap_errors), your best bet may be to subclass Greenlet and spawn that type. The exact steps aren't documented and are subject to change (they did change substantially between 1.0 and 1.1), but it can be done (I think, I haven't tried), probably even simpler than when this was originally written.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: wontfix Too expensive or difficult to fix
Projects
None yet
Development

No branches or pull requests

6 participants