Skip to content

Commit 5699960

Browse files
authored
Flask: Add Status Code Overwrite Safety (#235)
* Only set status code if it hasnt already been set * Yet another exceptin test
1 parent dc918f0 commit 5699960

File tree

4 files changed

+104
-8
lines changed

4 files changed

+104
-8
lines changed

instana/instrumentation/flask/vanilla.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ def teardown_request_with_instana(*argv, **kwargs):
8383
In the case of exceptions, after_request_with_instana isn't called
8484
so we capture those cases here.
8585
"""
86-
if hasattr(flask.g, 'scope'):
87-
if flask.g.scope is not None:
88-
if len(argv) > 0 and argv[0] is not None:
89-
scope = flask.g.scope
90-
scope.span.log_exception(argv[0])
86+
if hasattr(flask.g, 'scope') and flask.g.scope is not None:
87+
if len(argv) > 0 and argv[0] is not None:
88+
scope = flask.g.scope
89+
scope.span.log_exception(argv[0])
90+
if ext.HTTP_STATUS_CODE not in scope.span.tags:
9191
scope.span.set_tag(ext.HTTP_STATUS_CODE, 500)
92-
scope.close()
92+
flask.g.scope.close()
9393
flask.g.scope = None
9494

9595

instana/instrumentation/flask/with_blinker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,12 @@ def teardown_request_with_instana(*argv, **kwargs):
126126
In the case of exceptions, after_request_with_instana isn't called
127127
so we capture those cases here.
128128
"""
129-
130129
if hasattr(flask.g, 'scope') and flask.g.scope is not None:
131130
if len(argv) > 0 and argv[0] is not None:
132131
scope = flask.g.scope
133132
scope.span.log_exception(argv[0])
134-
scope.span.set_tag(ext.HTTP_STATUS_CODE, 500)
133+
if ext.HTTP_STATUS_CODE not in scope.span.tags:
134+
scope.span.set_tag(ext.HTTP_STATUS_CODE, 500)
135135
flask.g.scope.close()
136136
flask.g.scope = None
137137

tests/apps/flaskalino.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ def to_dict(self):
3939
return rv
4040

4141

42+
class NotFound(Exception):
43+
status_code = 404
44+
45+
def __init__(self, message, status_code=None, payload=None):
46+
Exception.__init__(self)
47+
self.message = message
48+
if status_code is not None:
49+
self.status_code = status_code
50+
self.payload = payload
51+
52+
def to_dict(self):
53+
rv = dict(self.payload or ())
54+
rv['message'] = self.message
55+
return rv
56+
57+
4258
@app.route("/")
4359
def hello():
4460
return "<center><h1>🐍 Hello Stan! 🦄</h1></center>"
@@ -86,6 +102,11 @@ def fourhundred():
86102
return "Simulated Bad Request", 400
87103

88104

105+
@app.route("/custom-404")
106+
def custom404():
107+
raise NotFound("My custom 404 message")
108+
109+
89110
@app.route("/405")
90111
def fourhundredfive():
91112
return "Simulated Method not allowed", 405
@@ -132,6 +153,7 @@ def response_headers():
132153
resp.headers['X-Capture-This'] = 'Ok'
133154
return resp
134155

156+
135157
@app.errorhandler(InvalidUsage)
136158
def handle_invalid_usage(error):
137159
logger.error("InvalidUsage error handler invoked")
@@ -140,6 +162,12 @@ def handle_invalid_usage(error):
140162
return response
141163

142164

165+
@app.errorhandler(404)
166+
@app.errorhandler(NotFound)
167+
def handle_not_found(e):
168+
return "blah: %s" % str(e), 404
169+
170+
143171
if __name__ == '__main__':
144172
flask_server.request_queue_size = 20
145173
flask_server.serve_forever()

tests/test_flask.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,74 @@ def test_301(self):
320320
# We should NOT have a path template for this route
321321
self.assertIsNone(wsgi_span.data["http"]["path_tpl"])
322322

323+
def test_custom_404(self):
324+
with tracer.start_active_span('test'):
325+
response = self.http.request('GET', testenv["wsgi_server"] + '/custom-404')
326+
327+
spans = self.recorder.queued_spans()
328+
329+
self.assertEqual(3, len(spans))
330+
331+
wsgi_span = spans[0]
332+
urllib3_span = spans[1]
333+
test_span = spans[2]
334+
335+
assert response
336+
self.assertEqual(404, response.status)
337+
338+
# assert('X-Instana-T' in response.headers)
339+
# assert(int(response.headers['X-Instana-T'], 16))
340+
# self.assertEqual(response.headers['X-Instana-T'], wsgi_span.t)
341+
#
342+
# assert('X-Instana-S' in response.headers)
343+
# assert(int(response.headers['X-Instana-S'], 16))
344+
# self.assertEqual(response.headers['X-Instana-S'], wsgi_span.s)
345+
#
346+
# assert('X-Instana-L' in response.headers)
347+
# self.assertEqual(response.headers['X-Instana-L'], '1')
348+
#
349+
# assert('Server-Timing' in response.headers)
350+
# server_timing_value = "intid;desc=%s" % wsgi_span.t
351+
# self.assertEqual(response.headers['Server-Timing'], server_timing_value)
352+
353+
self.assertIsNone(tracer.active_span)
354+
355+
# Same traceId
356+
self.assertEqual(test_span.t, urllib3_span.t)
357+
self.assertEqual(test_span.t, wsgi_span.t)
358+
359+
# Parent relationships
360+
self.assertEqual(urllib3_span.p, test_span.s)
361+
self.assertEqual(wsgi_span.p, urllib3_span.s)
362+
363+
# Error logging
364+
self.assertIsNone(test_span.ec)
365+
self.assertEqual(None, urllib3_span.ec)
366+
self.assertEqual(None, wsgi_span.ec)
367+
368+
# wsgi
369+
self.assertEqual("wsgi", wsgi_span.n)
370+
self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"])
371+
self.assertEqual('/custom-404', wsgi_span.data["http"]["url"])
372+
self.assertEqual('GET', wsgi_span.data["http"]["method"])
373+
self.assertEqual(404, wsgi_span.data["http"]["status"])
374+
self.assertIsNone(wsgi_span.data["http"]["error"])
375+
self.assertIsNotNone(wsgi_span.stack)
376+
self.assertEqual(2, len(wsgi_span.stack))
377+
378+
# urllib3
379+
self.assertEqual("test", test_span.data["sdk"]["name"])
380+
self.assertEqual("urllib3", urllib3_span.n)
381+
self.assertEqual(404, urllib3_span.data["http"]["status"])
382+
self.assertEqual(testenv["wsgi_server"] + '/custom-404', urllib3_span.data["http"]["url"])
383+
self.assertEqual("GET", urllib3_span.data["http"]["method"])
384+
self.assertIsNotNone(urllib3_span.stack)
385+
self.assertTrue(type(urllib3_span.stack) is list)
386+
self.assertTrue(len(urllib3_span.stack) > 1)
387+
388+
# We should NOT have a path template for this route
389+
self.assertIsNone(wsgi_span.data["http"]["path_tpl"])
390+
323391
def test_404(self):
324392
with tracer.start_active_span('test'):
325393
response = self.http.request('GET', testenv["wsgi_server"] + '/11111111111')

0 commit comments

Comments
 (0)