Commit f108a0f4 authored by Jason Madden's avatar Jason Madden

Include timestamp in error output. Fixes #137.

parent 84fce0ec
......@@ -57,6 +57,8 @@
longer print the entire WSGI environment by default. This avoids
possible information disclosure vulnerabilities. Originally reported
in :pr:`779` by sean-peters-au and changed in :pr:`781`.
- Unhandled exception reports that kill a greenlet print now include a
timestamp. See :issue:`137`.
1.1.0 (Mar 5, 2016)
===================
......
......@@ -69,3 +69,38 @@ def copy_globals(source,
del globs['copy_globals']
return copied
class Lazy(object):
"""
A non-data descriptor used just like @property. The
difference is the function value is assigned to the instance
dict the first time it is accessed and then the function is never
called agoin.
"""
def __init__(self, func):
self.data = (func, func.__name__)
def __get__(self, inst, class_):
if inst is None:
return self
func, name = self.data
value = func(inst)
inst.__dict__[name] = value
return value
class readproperty(object):
"""
A non-data descriptor like @property. The difference is that
when the property is assigned to, it is cached in the instance
and the function is not called on that instance again.
"""
def __init__(self, func):
self.func = func
def __get__(self, inst, class_):
if inst is None:
return self
return self.func(inst)
......@@ -5,6 +5,7 @@ from greenlet import greenlet
from gevent._compat import PY3
from gevent._compat import PYPY
from gevent._compat import reraise
from gevent._util import Lazy
from gevent._tblib import dump_traceback
from gevent._tblib import load_traceback
from gevent.hub import GreenletExit
......@@ -86,22 +87,6 @@ class FailureSpawnedLink(SpawnedLink):
if not source.successful():
return SpawnedLink.__call__(self, source)
class _lazy(object):
def __init__(self, func):
self.data = (func, func.__name__)
def __get__(self, inst, class_):
if inst is None:
return self
func, name = self.data
value = func(inst)
inst.__dict__[name] = value
return value
class Greenlet(greenlet):
"""A light-weight cooperatively-scheduled execution unit.
"""
......@@ -163,7 +148,7 @@ class Greenlet(greenlet):
def kwargs(self):
return self._kwargs or {}
@_lazy
@Lazy
def _links(self):
return deque()
......
......@@ -29,6 +29,7 @@ __all__ = [
from gevent._compat import string_types
from gevent._compat import xrange
from gevent._util import _NONE
from gevent._util import readproperty
if sys.version_info[0] <= 2:
import thread # pylint:disable=import-error
......@@ -567,14 +568,38 @@ class Hub(RawGreenlet):
if cb is not None:
cb.stop()
@readproperty
def exception_stream(self):
"""
The stream to which exceptions will be written.
Defaults to ``sys.stderr`` unless assigned to.
.. versionadded:: 1.2a1
"""
return sys.stderr
def print_exception(self, context, type, value, tb):
# Python 3 does not gracefully handle None value or tb in
# traceback.print_exception() as previous versions did.
# pylint:disable=no-member
errstream = self.exception_stream
if value is None:
sys.stderr.write('%s\n' % type.__name__)
errstream.write('%s\n' % type.__name__)
else:
traceback.print_exception(type, value, tb)
traceback.print_exception(type, value, tb, file=errstream)
del tb
try:
import time
errstream.write(time.ctime())
errstream.write(' ' if context is not None else '\n')
except: # pylint:disable=bare-except
# Possible not safe to import under certain
# error conditions in Python 2
pass
if context is not None:
if not isinstance(context, str):
try:
......@@ -582,7 +607,7 @@ class Hub(RawGreenlet):
except: # pylint:disable=bare-except
traceback.print_exc()
context = repr(context)
sys.stderr.write('%s failed with %s\n\n' % (context, getattr(type, '__name__', 'exception'), ))
errstream.write('%s failed with %s\n\n' % (context, getattr(type, '__name__', 'exception'), ))
def switch(self):
switch_out = getattr(getcurrent(), 'switch_out', None)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment