Skip to content

Commit 177d120

Browse files
committed
clean up tests
1 parent b83864a commit 177d120

File tree

11 files changed

+703
-66
lines changed

11 files changed

+703
-66
lines changed

ddtrace/contrib/internal/tornado/__init__.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
1616
# create your handlers
1717
class MainHandler(tornado.web.RequestHandler):
18-
@tornado.gen.coroutine
19-
def get(self):
18+
async def get(self):
2019
self.write("Hello, world")
2120
2221
# create your application
@@ -33,10 +32,9 @@ def get(self):
3332
the ``trace()`` method as usual::
3433
3534
class MainHandler(tornado.web.RequestHandler):
36-
@tornado.gen.coroutine
37-
def get(self):
38-
yield self.notify()
39-
yield self.blocking_method()
35+
async def get(self):
36+
await self.notify()
37+
await self.blocking_method()
4038
with tracer.trace('tornado.before_write') as span:
4139
# trace more work in the handler
4240
@@ -46,17 +44,15 @@ def blocking_method(self):
4644
# do something expensive
4745
4846
@tracer.wrap('tornado.notify', service='tornado-notification')
49-
@tornado.gen.coroutine
50-
def notify(self):
47+
async def notify(self):
5148
# do something
5249
5350
If you are overriding the ``on_finish`` or ``log_exception`` methods on a
5451
``RequestHandler``, you will need to call the super method to ensure the
5552
tracer's patched methods are called::
5653
5754
class MainHandler(tornado.web.RequestHandler):
58-
@tornado.gen.coroutine
59-
def get(self):
55+
async def get(self):
6056
self.write("Hello, world")
6157
6258
def on_finish(self):

ddtrace/contrib/internal/tornado/application.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,54 @@
66
from ddtrace import config
77
from ddtrace._trace.pin import Pin
88
from ddtrace.contrib.internal.tornado.constants import CONFIG_KEY
9+
from ddtrace.internal.logger import get_logger
910
from ddtrace.internal.schema import schematize_service_name
1011

1112

13+
log = get_logger(__name__)
14+
15+
16+
def _wrap_executor(tracer, fn, args, kwargs, span_name, service=None, resource=None, span_type=None):
17+
span = tracer.trace(span_name, service=service, resource=resource, span_type=span_type)
18+
prev_active = tracer.context_provider.active()
19+
20+
def _finish_span(future):
21+
try:
22+
exc = future.exception()
23+
if exc is not None:
24+
span.set_exc_info(type(exc), exc, exc.__traceback__)
25+
except Exception:
26+
try:
27+
future.result()
28+
except Exception:
29+
span.set_traceback()
30+
finally:
31+
tracer.context_provider.activate(prev_active)
32+
span.finish()
33+
34+
try:
35+
result = fn(*args, **kwargs)
36+
if callable(getattr(result, "add_done_callback", None)):
37+
tracer.context_provider.activate(span)
38+
result.add_done_callback(_finish_span)
39+
else:
40+
span.finish()
41+
return result
42+
except Exception:
43+
span.set_traceback()
44+
span.finish()
45+
raise
46+
47+
48+
def _wrapped_sleep(wrapped, instance, args, kwargs):
49+
log.warning(
50+
"ddtrace does not support tornado.gen.sleep. Its usage can impact span parenting and trace accuracy. "
51+
"With Tornado >6.1 being asyncio-based, tornado.gen.sleep is no longer supported. "
52+
"Please migrate to asyncio.sleep() instead."
53+
)
54+
return wrapped(*args, **kwargs)
55+
56+
1257
def tracer_config(__init__, app, args, kwargs):
1358
"""
1459
Wrap Tornado web application so that we can configure services info and

ddtrace/contrib/internal/tornado/constants.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@
55

66
CONFIG_KEY = "datadog_trace"
77
REQUEST_SPAN_KEY = "__datadog_request_span"
8-
FUTURE_SPAN_KEY = "__datadog_future_span"

ddtrace/contrib/internal/tornado/patch.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from wrapt import wrap_function_wrapper as _w
66

77
from ddtrace import config
8+
from ddtrace import tracer
89
from ddtrace.internal.utils.formats import asbool
910
from ddtrace.internal.utils.wrappers import unwrap as _u
1011

@@ -30,39 +31,41 @@ def _supported_versions() -> Dict[str, str]:
3031
return {"tornado": ">=6.1"}
3132

3233

34+
DEFAULT_WRAP_EXECUTOR = None
35+
36+
3337
def patch():
34-
"""
35-
Tracing function that patches the Tornado web application so that it will be
36-
traced using the given ``tracer``.
37-
"""
38-
# patch only once
3938
if getattr(tornado, "__datadog_patch", False):
4039
return
4140
tornado.__datadog_patch = True
41+
global DEFAULT_WRAP_EXECUTOR
42+
DEFAULT_WRAP_EXECUTOR = getattr(tracer, "_wrap_executor", None)
43+
tracer._wrap_executor = application._wrap_executor
4244

43-
# patch Application to initialize properly our settings and tracer
4445
_w("tornado.web", "Application.__init__", application.tracer_config)
45-
46-
# patch RequestHandler to trace all Tornado handlers
4746
_w("tornado.web", "RequestHandler._execute", handlers.execute)
4847
_w("tornado.web", "RequestHandler.on_finish", handlers.on_finish)
4948
_w("tornado.web", "RequestHandler.log_exception", handlers.log_exception)
50-
51-
# patch Template system
5249
_w("tornado.template", "Template.generate", template.generate)
50+
# wrapt handles lazy imports, so we can wrap even if tornado.gen isn't imported yet
51+
try:
52+
_w("tornado.gen", "sleep", application._wrapped_sleep)
53+
except (ImportError, AttributeError):
54+
pass
5355

5456

5557
def unpatch():
56-
"""
57-
Remove all tracing functions in a Tornado web application.
58-
"""
5958
if not getattr(tornado, "__datadog_patch", False):
6059
return
6160
tornado.__datadog_patch = False
6261

63-
# unpatch Tornado
62+
tracer._wrap_executor = DEFAULT_WRAP_EXECUTOR
63+
6464
_u(tornado.web.RequestHandler, "_execute")
6565
_u(tornado.web.RequestHandler, "on_finish")
6666
_u(tornado.web.RequestHandler, "log_exception")
6767
_u(tornado.web.Application, "__init__")
6868
_u(tornado.template.Template, "generate")
69+
# Use getattr to avoid creating a local variable that shadows the module-level import
70+
if getattr(tornado, "gen", None) and hasattr(tornado.gen, "sleep"):
71+
_u(tornado.gen, "sleep")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
fixes:
3+
- |
4+
tornado: Fixed ``tracer.wrap()`` to correctly measure span durations for Tornado coroutines and
5+
functions that return Futures, ensuring spans complete only after the asynchronous operation finishes.
6+
``tornado.gen.sleep`` is no longer supported for Tornado >=6.1; a warning will be logged if used.
7+
Users should migrate to ``asyncio.sleep``.
8+

0 commit comments

Comments
 (0)