Skip to content

Commit

Permalink
sanic: test response header capture
Browse files Browse the repository at this point in the history
Signed-off-by: Varsha GS <varsha.gs@ibm.com>
  • Loading branch information
GSVarsha committed Feb 14, 2024
1 parent f51d42d commit f557fe7
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 28 deletions.
43 changes: 22 additions & 21 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ commands:
GEVENT_TEST: "<<parameters.gevent>>"
command: |
. venv/bin/activate
coverage run --source=instana -m pytest -v --junitxml=test-results <<parameters.tests>>
coverage run --source=instana -m pytest -v --junitxml=test-results <<parameters.tests>> -s
coverage report -m
coverage html
mkdir coverage_results
Expand Down Expand Up @@ -210,7 +210,8 @@ jobs:
- checkout
- pip-install-deps:
requirements: "tests/requirements-310.txt"
- run-tests-with-coverage-report
- run-tests-with-coverage-report:
tests: "tests/frameworks/test_sanic.py"
- store-pytest-results
- store-coverage-report

Expand Down Expand Up @@ -329,23 +330,23 @@ workflows:
version: 2
build:
jobs:
- python37
- python38
- python39
# - python37
# - python38
# - python39
- python310
- python311
- python312
- py39cassandra
- py39couchbase
- py39gevent
- final_job:
requires:
- python37
- python38
- python39
- python310
- python311
- python312
- py39cassandra
- py39couchbase
- py39gevent
# - python311
# - python312
# - py39cassandra
# - py39couchbase
# - py39gevent
# - final_job:
# requires:
# - python37
# - python38
# - python39
# - python310
# - python311
# - python312
# - py39cassandra
# - py39couchbase
# - py39gevent
3 changes: 2 additions & 1 deletion instana/instrumentation/sanic_inst.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def response_details(span, response):
span.set_tag('http.status_code', status_code)

if response.headers is not None:
extract_custom_headers(span, response.headers)
async_tracer.inject(span.context, opentracing.Format.HTTP_HEADERS, response.headers)
response.headers['Server-Timing'] = "intid;desc=%s" % span.context.trace_id
except Exception:
Expand Down Expand Up @@ -124,7 +125,7 @@ async def handle_request_with_instana(wrapped, instance, args, kwargs):
scope.span.set_tag("http.params", scrubbed_params)

if agent.options.extra_http_headers is not None:
extract_custom_headers(scope, headers)
extract_custom_headers(scope.span, headers)
await wrapped(*args, **kwargs)
if hasattr(request, "uri_template") and request.uri_template:
scope.span.set_tag("http.path_tpl", request.uri_template)
Expand Down
4 changes: 2 additions & 2 deletions instana/util/traceutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
from ..log import logger


def extract_custom_headers(tracing_scope, headers):
def extract_custom_headers(tracing_span, headers):
try:
for custom_header in agent.options.extra_http_headers:
# Headers are in the following format: b'x-header-1'
for header_key, value in headers.items():
if header_key.lower() == custom_header.lower():
tracing_scope.span.set_tag("http.header.%s" % custom_header, value)
tracing_span.set_tag("http.header.%s" % custom_header, value)
except Exception:
logger.debug("extract_custom_headers: ", exc_info=True)

Expand Down
15 changes: 13 additions & 2 deletions tests/apps/sanic_app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


import uvicorn

from ...helpers import testenv
from instana.log import logger

Expand All @@ -15,6 +16,16 @@ def launch_sanic():
from instana.singletons import agent

# Hack together a manual custom headers list; We'll use this in tests
agent.options.extra_http_headers = [u'X-Capture-This', u'X-Capture-That']
agent.options.extra_http_headers = [
"X-Capture-This",
"X-Capture-That",
"X-Capture-This-Too",
"X-Capture-That-Too",
]

uvicorn.run(app, host='127.0.0.1', port=testenv['sanic_port'], log_level="critical")
uvicorn.run(
app,
host="127.0.0.1",
port=testenv["sanic_port"],
log_level="critical",
)
10 changes: 9 additions & 1 deletion tests/apps/sanic_app/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@

from sanic import Sanic
from sanic.exceptions import SanicException
from sanic.response import text

from tests.apps.sanic_app.simpleview import SimpleView
from tests.apps.sanic_app.name import NameView
from sanic.response import text

app = Sanic('test')

@app.get("/foo/<foo_id:int>")
async def uuid_handler(request, foo_id: int):
return text("INT - {}".format(foo_id))

@app.route("/response_headers")
async def response_headers(request):
headers = {
'X-Capture-This-Too': 'this too',
'X-Capture-That-Too': 'that too'
}
return text("Stan wuz here with headers!", headers=headers)

@app.route("/test_request_args")
async def test_request_args(request):
Expand Down
54 changes: 53 additions & 1 deletion tests/frameworks/test_sanic.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ def test_synthetic_request(self):
self.assertIsNone(urllib3_span.sy)
self.assertIsNone(test_span.sy)

def test_custom_header_capture(self):
def test_request_header_capture(self):
request_headers = {
'X-Capture-This': 'this',
'X-Capture-That': 'that'
Expand Down Expand Up @@ -441,3 +441,55 @@ def test_custom_header_capture(self):
assert ("this" == asgi_span.data["http"]["header"]["X-Capture-This"])
assert ("X-Capture-That" in asgi_span.data["http"]["header"])
assert ("that" == asgi_span.data["http"]["header"]["X-Capture-That"])

def test_response_header_capture(self):
with tracer.start_active_span("test"):
result = requests.get(testenv["sanic_server"] + "/response_headers")

print(result)
self.assertEqual(result.status_code, 200)

spans = tracer.recorder.queued_spans()
self.assertEqual(len(spans), 3)

span_filter = lambda span: span.n == "sdk" and span.data['sdk']['name'] == 'test'
test_span = get_first_span_by_filter(spans, span_filter)
self.assertIsNotNone(test_span)

span_filter = lambda span: span.n == "urllib3"
urllib3_span = get_first_span_by_filter(spans, span_filter)
self.assertIsNotNone(urllib3_span)

span_filter = lambda span: span.n == 'asgi'
asgi_span = get_first_span_by_filter(spans, span_filter)
self.assertIsNotNone(asgi_span)

print("#######span#####")
print(asgi_span.data)

self.assertTraceContextPropagated(test_span, urllib3_span)
self.assertTraceContextPropagated(urllib3_span, asgi_span)

self.assertIn("X-INSTANA-T", result.headers)
self.assertEqual(result.headers["X-INSTANA-T"], asgi_span.t)
self.assertIn("X-INSTANA-S", result.headers)
self.assertEqual(result.headers["X-INSTANA-S"], asgi_span.s)
self.assertIn("X-INSTANA-L", result.headers)
self.assertEqual(result.headers["X-INSTANA-L"], '1')
self.assertIn("Server-Timing", result.headers)
self.assertEqual(result.headers["Server-Timing"], ("intid;desc=%s" % asgi_span.t))

self.assertIsNone(asgi_span.ec)
assert (asgi_span.data['http']['host'] == '127.0.0.1:1337')
self.assertEqual(asgi_span.data["http"]["path"], "/response_headers")
self.assertEqual(asgi_span.data["http"]["path_tpl"], "/response_headers")
self.assertEqual(asgi_span.data["http"]["method"], "GET")
self.assertEqual(asgi_span.data["http"]["status"], 200)

self.assertIsNone(asgi_span.data["http"]["error"])
self.assertIsNone(asgi_span.data["http"]["params"])

self.assertIn("X-Capture-This-Too", asgi_span.data["http"]["header"])
self.assertEqual("this too", asgi_span.data["http"]["header"]["X-Capture-This-Too"])
self.assertIn("X-Capture-That-Too", asgi_span.data["http"]["header"])
self.assertEqual("that too", asgi_span.data["http"]["header"]["X-Capture-That-Too"])

0 comments on commit f557fe7

Please sign in to comment.