Skip to content

Commit 428d605

Browse files
authored
urllib3: Capture response headers when requested (#210)
1 parent 36fb3d9 commit 428d605

File tree

3 files changed

+86
-9
lines changed

3 files changed

+86
-9
lines changed

instana/instrumentation/urllib3.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,23 @@ def collect(instance, args, kwargs):
4444
else:
4545
return kvs
4646

47+
def collect_response(scope, response):
48+
try:
49+
scope.span.set_tag(ext.HTTP_STATUS_CODE, response.status)
50+
51+
if agent.extra_headers is not None:
52+
for custom_header in agent.extra_headers:
53+
if custom_header in response.headers:
54+
scope.span.set_tag("http.%s" % custom_header, response.headers[custom_header])
55+
56+
if 500 <= response.status <= 599:
57+
scope.span.set_tag("error", True)
58+
ec = scope.span.tags.get('ec', 0)
59+
scope.span.set_tag("ec", ec + 1)
60+
except Exception:
61+
logger.debug("collect_response", exc_info=True)
62+
63+
4764
@wrapt.patch_function_wrapper('urllib3', 'HTTPConnectionPool.urlopen')
4865
def urlopen_with_instana(wrapped, instance, args, kwargs):
4966
parent_span = tracer.active_span
@@ -65,15 +82,11 @@ def urlopen_with_instana(wrapped, instance, args, kwargs):
6582
if 'headers' in kwargs:
6683
tracer.inject(scope.span.context, opentracing.Format.HTTP_HEADERS, kwargs['headers'])
6784

68-
rv = wrapped(*args, **kwargs)
85+
response = wrapped(*args, **kwargs)
6986

70-
scope.span.set_tag(ext.HTTP_STATUS_CODE, rv.status)
71-
if 500 <= rv.status <= 599:
72-
scope.span.set_tag("error", True)
73-
ec = scope.span.tags.get('ec', 0)
74-
scope.span.set_tag("ec", ec+1)
87+
collect_response(scope, response)
7588

76-
return rv
89+
return response
7790
except Exception as e:
7891
scope.span.log_kv({'message': e})
7992
scope.span.set_tag("error", True)

tests/apps/flaskalino.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import opentracing.ext.tags as ext
44
from flask import Flask, redirect, render_template, render_template_string
55
from wsgiref.simple_server import make_server
6-
from flask import jsonify
6+
from flask import jsonify, Response
77

88
from instana.singletons import tracer
99
from ..helpers import testenv
@@ -121,6 +121,12 @@ def render_error():
121121
return render_template('flask_render_error.html', what='world')
122122

123123

124+
@app.route("/response_headers")
125+
def response_headers():
126+
resp = Response("Foo bar baz")
127+
resp.headers['X-Capture-This'] = 'Ok'
128+
return resp
129+
124130
@app.errorhandler(InvalidUsage)
125131
def handle_invalid_usage(error):
126132
logger.error("InvalidUsage error handler invoked")

tests/test_urllib3.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import requests
66
import urllib3
77

8-
from instana.singletons import tracer
8+
from instana.singletons import agent, tracer
99
from .helpers import testenv
1010

1111

@@ -692,3 +692,61 @@ def test_requestspkg_put(self):
692692
self.assertIsNotNone(urllib3_span.stack)
693693
self.assertTrue(type(urllib3_span.stack) is list)
694694
self.assertTrue(len(urllib3_span.stack) > 1)
695+
696+
def test_response_header_capture(self):
697+
original_extra_headers = agent.extra_headers
698+
agent.extra_headers = ['X-Capture-This']
699+
700+
with tracer.start_active_span('test'):
701+
r = self.http.request('GET', testenv["wsgi_server"] + '/response_headers')
702+
703+
spans = self.recorder.queued_spans()
704+
self.assertEqual(3, len(spans))
705+
706+
wsgi_span = spans[0]
707+
urllib3_span = spans[1]
708+
test_span = spans[2]
709+
710+
assert(r)
711+
self.assertEqual(200, r.status)
712+
self.assertIsNone(tracer.active_span)
713+
714+
# Same traceId
715+
self.assertEqual(test_span.t, urllib3_span.t)
716+
self.assertEqual(urllib3_span.t, wsgi_span.t)
717+
718+
# Parent relationships
719+
self.assertEqual(urllib3_span.p, test_span.s)
720+
self.assertEqual(wsgi_span.p, urllib3_span.s)
721+
722+
# Error logging
723+
self.assertFalse(test_span.error)
724+
self.assertIsNone(test_span.ec)
725+
self.assertFalse(urllib3_span.error)
726+
self.assertIsNone(urllib3_span.ec)
727+
self.assertFalse(wsgi_span.error)
728+
self.assertIsNone(wsgi_span.ec)
729+
730+
# wsgi
731+
self.assertEqual("wsgi", wsgi_span.n)
732+
self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host)
733+
self.assertEqual('/response_headers', wsgi_span.data.http.url)
734+
self.assertEqual('GET', wsgi_span.data.http.method)
735+
self.assertEqual(200, wsgi_span.data.http.status)
736+
self.assertIsNone(wsgi_span.data.http.error)
737+
self.assertIsNotNone(wsgi_span.stack)
738+
self.assertEqual(2, len(wsgi_span.stack))
739+
740+
# urllib3
741+
self.assertEqual("test", test_span.data.sdk.name)
742+
self.assertEqual("urllib3", urllib3_span.n)
743+
self.assertEqual(200, urllib3_span.data.http.status)
744+
self.assertEqual(testenv["wsgi_server"] + "/response_headers", urllib3_span.data.http.url)
745+
self.assertEqual("GET", urllib3_span.data.http.method)
746+
self.assertIsNotNone(urllib3_span.stack)
747+
self.assertTrue(type(urllib3_span.stack) is list)
748+
self.assertTrue(len(urllib3_span.stack) > 1)
749+
self.assertTrue('http.X-Capture-This' in urllib3_span.data.custom.tags)
750+
751+
agent.extra_headers = original_extra_headers
752+

0 commit comments

Comments
 (0)