Skip to content
This repository was archived by the owner on Jun 13, 2023. It is now read-only.

Commit b1ca110

Browse files
authored
fix(tornado.py): fix mishandling of 404s (#317)
1 parent dbaf1aa commit b1ca110

9 files changed

Lines changed: 101 additions & 18 deletions

File tree

epsagon/events/redis.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from ..event import BaseEvent
1010
from ..trace import trace_factory
11+
from ..utils import add_data_if_needed
12+
1113

1214
MAX_VALUE_SIZE = 1024
1315
MAX_CMD_PIPELINE = 10
@@ -110,6 +112,13 @@ def __init__(self, wrapped, instance, args, kwargs, start_time, response,
110112
self.resource['operation'] = operation
111113
self.resource['metadata']['Redis Key'] = key
112114

115+
if response:
116+
add_data_if_needed(
117+
self.resource['metadata'],
118+
'redis.response',
119+
response
120+
)
121+
113122

114123
class RedisMultiExecutionEvent(BaseRedisEvent):
115124
"""

epsagon/modules/logging.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import wrapt
1212

1313
from ..trace import trace_factory
14-
from ..utils import print_debug
14+
from ..utils import print_debug, get_trace_log_config
1515

1616
LOGGING_FUNCTIONS = (
1717
'info',
@@ -99,7 +99,7 @@ def patch():
9999
wrapt.wrap_function_wrapper('logging', 'Logger.exception', _wrapper)
100100

101101
# Instrument logging with Epsagon trace ID
102-
if trace_factory.is_logging_tracing_enabled():
102+
if get_trace_log_config():
103103
wrapt.wrap_function_wrapper(
104104
'logging',
105105
'Logger.log',

epsagon/modules/redis.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,9 @@ def patch():
5454
'Pipeline.execute',
5555
_multi_wrapper
5656
)
57+
# Version < 3.0
58+
wrapt.wrap_function_wrapper(
59+
'redis',
60+
'StrictRedis.execute_command',
61+
_single_wrapper
62+
)

epsagon/modules/tornado.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import epsagon.trace
1212
from epsagon.runners.tornado import TornadoRunner
1313
from epsagon.http_filters import ignore_request, is_ignored_endpoint
14-
from epsagon.utils import collect_container_metadata
14+
from epsagon.utils import collect_container_metadata, print_debug
1515

1616
TORNADO_TRACE_ID = 'epsagon_tornado_trace_key'
1717

@@ -31,6 +31,7 @@ def before_request(cls, wrapped, instance, args, kwargs):
3131
:param args: wrapt's args
3232
:param kwargs: wrapt's kwargs
3333
"""
34+
print_debug('before_request Tornado request')
3435
try:
3536
ignored = ignore_request('', instance.request.path)
3637
if not ignored and not is_ignored_endpoint(instance.request.path):
@@ -48,6 +49,7 @@ def before_request(cls, wrapped, instance, args, kwargs):
4849
)
4950

5051
trace.set_runner(cls.RUNNERS[unique_id])
52+
print_debug('Created Tornado Runner')
5153

5254
# Collect metadata in case this is a container.
5355
collect_container_metadata(
@@ -69,9 +71,18 @@ def after_request(cls, wrapped, instance, args, kwargs):
6971
:param args: wrapt's args
7072
:param kwargs: wrapt's kwargs
7173
"""
72-
response_body = getattr(instance, '_write_buffer', None)
73-
if response_body and isinstance(response_body, list):
74-
response_body = b''.join(response_body)
74+
print_debug('after_request Tornado request')
75+
response_body = None
76+
try:
77+
response_body = getattr(instance, '_write_buffer', None)
78+
if response_body and isinstance(response_body, list):
79+
response_body = b''.join(response_body)
80+
except Exception as instrumentation_exception: # pylint: disable=W0703
81+
epsagon.trace.trace_factory.add_exception(
82+
instrumentation_exception,
83+
traceback.format_exc()
84+
)
85+
7586
res = wrapped(*args, **kwargs)
7687
try:
7788
unique_id = getattr(instance, TORNADO_TRACE_ID, None)
@@ -84,6 +95,12 @@ def after_request(cls, wrapped, instance, args, kwargs):
8495
unique_id
8596
)
8697

98+
# Ignoring 404s
99+
if getattr(instance, '_status_code', None) == 404:
100+
epsagon.trace.trace_factory.pop_trace(trace=trace)
101+
print_debug('Ignoring 404 Tornado request')
102+
return res
103+
87104
if trace:
88105
content = (
89106
instance._headers.get( # pylint: disable=protected-access
@@ -111,6 +128,7 @@ def collect_exception(cls, wrapped, instance, args, kwargs):
111128
:param args: wrapt's args
112129
:param kwargs: wrapt's kwargs
113130
"""
131+
print_debug('collect_exception Tornado request')
114132
try:
115133
unique_id = getattr(instance, TORNADO_TRACE_ID, None)
116134

epsagon/runners/aiohttp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def __init__(self, start_time, request, body, handler):
3939
'Base URL': request.url.host,
4040
'Path': request.url.path,
4141
'User Agent': request.headers.get('User-Agent', 'N/A'),
42-
'Endpoint': handler.__name__,
42+
'Endpoint': getattr(handler, '__name__', ''),
4343
})
4444

4545
if request.query_string:

epsagon/runners/tornado.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from __future__ import absolute_import
77
import uuid
88
from ..event import BaseEvent
9-
from ..utils import add_data_if_needed
9+
from ..utils import add_data_if_needed, print_debug
1010
from ..constants import EPSAGON_HEADER_TITLE
1111

1212
MAX_PAYLOAD_BYTES = 2000
@@ -69,6 +69,19 @@ def __init__(self, start_time, request):
6969
request_headers
7070
)
7171

72+
try:
73+
if request.body:
74+
body = request.body
75+
if isinstance(body, bytes):
76+
body = body.decode('utf-8')
77+
add_data_if_needed(
78+
self.resource['metadata'],
79+
'Request Data',
80+
body
81+
)
82+
except Exception as exception: # pylint: disable=broad-except
83+
print_debug('Could not extract request body: {}'.format(exception))
84+
7285
def update_response(self, response, response_body=None):
7386
"""
7487
Adds response data to event.
@@ -83,10 +96,16 @@ def update_response(self, response, response_body=None):
8396
)
8497

8598
if response_body:
99+
body = response_body
100+
if isinstance(body, list):
101+
body = body[0]
102+
if isinstance(body, bytes):
103+
body = body.decode('utf-8')
104+
86105
add_data_if_needed(
87106
self.resource['metadata'],
88107
'Response Body',
89-
str(response_body)[:MAX_PAYLOAD_BYTES]
108+
str(body)[:MAX_PAYLOAD_BYTES]
90109
)
91110

92111
self.resource['metadata']['status_code'] = response._status_code

epsagon/utils.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ def get_tc_url(use_ssl):
9595
return TRACE_COLLECTOR_URL.format(protocol=protocol, region=REGION)
9696

9797

98+
def get_trace_log_config():
99+
"""Returns the trace log correlation configuration"""
100+
# In case we're running on AWS Lambda, logging correlation is disabled
101+
if is_lambda_env():
102+
return False
103+
104+
# If EPSAGON_LOGGING_TRACING_ENABLED exists as an env var - use it
105+
if os.getenv('EPSAGON_LOGGING_TRACING_ENABLED'):
106+
return os.getenv('EPSAGON_LOGGING_TRACING_ENABLED').upper() == 'TRUE'
107+
108+
return True
109+
110+
98111
def init(
99112
token='',
100113
app_name='Application',
@@ -174,15 +187,7 @@ def init(
174187
if os.getenv('EPSAGON_METADATA'):
175188
metadata_only = (os.getenv('EPSAGON_METADATA') or '').upper() == 'TRUE'
176189

177-
# If EPSAGON_LOGGING_TRACING_ENABLED exists as an env var - use it
178-
if os.getenv('EPSAGON_LOGGING_TRACING_ENABLED'):
179-
logging_tracing_enabled = (
180-
os.getenv('EPSAGON_LOGGING_TRACING_ENABLED') or ''
181-
).upper() == 'TRUE'
182-
183-
# In case we're running on AWS Lambda, logging correlation is disabled
184-
if is_lambda_env():
185-
logging_tracing_enabled = False
190+
logging_tracing_enabled = get_trace_log_config()
186191

187192
if os.getenv('EPSAGON_SAMPLE_RATE'):
188193
sample_rate = float(os.getenv('EPSAGON_SAMPLE_RATE'))

epsagon/wrappers/aiohttp.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import time
77
import warnings
88
from aiohttp.web import middleware
9+
from aiohttp.web_exceptions import HTTPNotFound
910

1011
import epsagon.trace
1112
import epsagon.triggers.http
@@ -16,6 +17,7 @@
1617
get_traceback_data_from_exception
1718
)
1819
from ..http_filters import ignore_request
20+
from ..utils import print_debug
1921

2022

2123
@middleware
@@ -26,9 +28,11 @@ async def AiohttpMiddleware(request, handler):
2628
:param handler: original handler
2729
:return: response data from the handler
2830
"""
31+
print_debug('[aiohttp] started middleware')
2932
epsagon.trace.trace_factory.switch_to_async_tracer()
3033

3134
if ignore_request('', request.path.lower()):
35+
print_debug('[aiohttp] ignoring request')
3236
return await handler(request)
3337

3438
trace = epsagon.trace.trace_factory.get_or_create_trace()
@@ -38,15 +42,22 @@ async def AiohttpMiddleware(request, handler):
3842

3943
try:
4044
body = await request.text()
45+
print_debug('[aiohttp] got body')
4146
runner = AiohttpRunner(time.time(), request, body, handler)
4247
trace.set_runner(runner)
4348
collect_container_metadata(runner.resource['metadata'])
49+
print_debug('[aiohttp] initialized runner')
4450
except Exception as exception: # pylint: disable=W0703
4551
warnings.warn('Could not extract request', EpsagonWarning)
4652

4753
raised_err = None
4854
try:
4955
response = await handler(request)
56+
print_debug('[aiohttp] got response')
57+
except HTTPNotFound:
58+
# Ignoring 404s
59+
epsagon.trace.trace_factory.pop_trace(trace)
60+
raise
5061
except Exception as exception: # pylint: disable=W0703
5162
raised_err = exception
5263
traceback_data = get_traceback_data_from_exception(exception)
@@ -59,7 +70,10 @@ async def AiohttpMiddleware(request, handler):
5970
runner.update_response(response)
6071

6172
if runner:
73+
print_debug('[aiohttp] sending trace')
6274
epsagon.trace.trace_factory.send_traces()
6375
if raised_err:
76+
print_debug('[aiohttp] raising error')
6477
raise raised_err
78+
print_debug('[aiohttp] middleware done')
6579
return response

tests/wrappers/test_aiohttp_wrapper.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,15 @@ async def test_aiohttp_exception(_, trace_transport, aiohttp_client):
5353
assert runner.error_code == ErrorCode.EXCEPTION
5454
assert runner.exception['type'] == 'CustomAioHttpException'
5555
assert runner.exception['message'] == 'test'
56+
57+
58+
@asynctest.patch('epsagon.trace.trace_factory.use_async_tracer')
59+
async def test_aiohttp_no_endpoint(_, trace_transport, aiohttp_client):
60+
"""Test when no route exists (404)."""
61+
client = await aiohttp_client(create_app)
62+
response = await client.get('/not/exists')
63+
assert response.status == 404
64+
# Trace not sent
65+
trace_transport.send.assert_not_called()
66+
# Trace removed
67+
assert trace_transport.last_trace is None

0 commit comments

Comments
 (0)