Skip to content

Commit e27e8a4

Browse files
authored
Check for missing elasticapm_client in tornado instrumentation (#813)
* Check for missing elasticapm_client in tornado instrumentation * Add a test
1 parent 5cdb443 commit e27e8a4

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

elasticapm/instrumentation/packages/tornado.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ class TornadoRequestExecuteInstrumentation(AsyncAbstractInstrumentedModule):
4343
instrument_list = [("tornado.web", "RequestHandler._execute")]
4444

4545
async def call(self, module, method, wrapped, instance, args, kwargs):
46+
if not hasattr(instance.application, "elasticapm_client"):
47+
# If tornado was instrumented but not as the main framework
48+
# (i.e. in Flower), we should skip it.
49+
return await wrapped(*args, **kwargs)
50+
4651
# Late import to avoid ImportErrors
4752
from elasticapm.contrib.tornado.utils import get_data_from_request, get_data_from_response
4853

@@ -74,6 +79,10 @@ class TornadoHandleRequestExceptionInstrumentation(AbstractInstrumentedModule):
7479
instrument_list = [("tornado.web", "RequestHandler._handle_request_exception")]
7580

7681
def call(self, module, method, wrapped, instance, args, kwargs):
82+
if not hasattr(instance.application, "elasticapm_client"):
83+
# If tornado was instrumented but not as the main framework
84+
# (i.e. in Flower), we should skip it.
85+
return wrapped(*args, **kwargs)
7786

7887
# Late import to avoid ImportErrors
7988
from tornado.web import Finish, HTTPError

tests/contrib/asyncio/tornado/tornado_tests.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,36 @@ def get(self):
7575
return app
7676

7777

78+
@pytest.fixture
79+
def app_no_client():
80+
class HelloHandler(tornado.web.RequestHandler):
81+
def get(self):
82+
with async_capture_span("test"):
83+
pass
84+
return self.write("Hello, world")
85+
86+
post = get
87+
88+
class RenderHandler(tornado.web.RequestHandler):
89+
def get(self):
90+
with async_capture_span("test"):
91+
pass
92+
items = ["Item 1", "Item 2", "Item 3"]
93+
return self.render("test.html", title="Testing so hard", items=items)
94+
95+
class BoomHandler(tornado.web.RequestHandler):
96+
def get(self):
97+
raise tornado.web.HTTPError()
98+
99+
post = get
100+
101+
app = tornado.web.Application(
102+
[(r"/", HelloHandler), (r"/boom", BoomHandler), (r"/render", RenderHandler)],
103+
template_path=os.path.join(os.path.dirname(__file__), "templates"),
104+
)
105+
return app
106+
107+
78108
@pytest.mark.gen_test
79109
async def test_get(app, base_url, http_client):
80110
elasticapm_client = app.elasticapm_client
@@ -196,3 +226,15 @@ async def test_capture_headers_body_is_dynamic(app, base_url, http_client):
196226
assert transactions[2]["context"]["request"]["body"] == "[REDACTED]"
197227
assert "headers" not in errors[1]["context"]["request"]
198228
assert errors[1]["context"]["request"]["body"] == "[REDACTED]"
229+
230+
231+
@pytest.mark.gen_test
232+
async def test_no_elasticapm_client(app_no_client, base_url, http_client, elasticapm_client):
233+
"""
234+
Need to make sure instrumentation works even when tornado is not
235+
explicitly using the agent
236+
"""
237+
elasticapm_client.begin_transaction("test")
238+
response = await http_client.fetch(base_url)
239+
assert response.code == 200
240+
elasticapm_client.end_transaction("test")

0 commit comments

Comments
 (0)