Skip to content

Commit 82d1861

Browse files
committed
fastapi: capture responseHeadersOnEntrySpans
Signed-off-by: Varsha GS <[email protected]>
1 parent 6293143 commit 82d1861

File tree

4 files changed

+66
-9
lines changed

4 files changed

+66
-9
lines changed

instana/instrumentation/asgi.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ def __init__(self, app):
2121

2222
def _extract_custom_headers(self, span, headers):
2323
try:
24-
for custom_header in agent.options.extra_http_headers:
25-
# Headers are in the following format: b'x-header-1'
26-
for header_pair in headers:
27-
if header_pair[0].decode('utf-8').lower() == custom_header.lower():
28-
span.set_tag("http.header.%s" % custom_header, header_pair[1].decode('utf-8'))
24+
if agent.options.extra_http_headers is not None:
25+
for custom_header in agent.options.extra_http_headers:
26+
# Headers are in the following format: b'x-header-1'
27+
for header_pair in headers:
28+
if header_pair[0].decode('utf-8').lower() == custom_header.lower():
29+
span.set_tag("http.header.%s" % custom_header, header_pair[1].decode('utf-8'))
2930
except Exception:
3031
logger.debug("extract_custom_headers: ", exc_info=True)
3132

@@ -84,6 +85,7 @@ async def send_wrapper(response):
8485

8586
headers = response.get('headers')
8687
if headers is not None:
88+
self._extract_custom_headers(span, headers)
8789
async_tracer.inject(span.context, opentracing.Format.BINARY, headers)
8890
except Exception:
8991
logger.debug("send_wrapper: ", exc_info=True)

tests/apps/fastapi_app/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ def launch_fastapi():
1313
from instana.singletons import agent
1414

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

1818
uvicorn.run(fastapi_server, host='127.0.0.1', port=testenv['fastapi_port'], log_level="critical")

tests/apps/fastapi_app/app.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# (c) Copyright IBM Corp. 2021
22
# (c) Copyright Instana Inc. 2020
33

4-
from fastapi import FastAPI, HTTPException
4+
from fastapi import FastAPI, HTTPException, Response
55
from fastapi.exceptions import RequestValidationError
66
from fastapi.responses import PlainTextResponse
77
from starlette.exceptions import HTTPException as StarletteHTTPException
@@ -24,6 +24,11 @@ async def root():
2424
async def user(user_id):
2525
return {"user": user_id}
2626

27+
@fastapi_server.get("/response_headers")
28+
async def response_headers():
29+
headers = {'X-Capture-This-Too': 'this too'}
30+
return Response(content=None, headers=headers)
31+
2732
@fastapi_server.get("/400")
2833
async def four_zero_zero():
2934
raise HTTPException(status_code=400, detail="400 response")

tests/frameworks/test_fastapi.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,15 @@ def test_synthetic_request(server):
311311
assert (test_span.sy is None)
312312

313313

314-
def test_custom_header_capture(server):
315-
from instana.singletons import agent
314+
def test_request_header_capture(server):
316315

317316
# The background FastAPI server is pre-configured with custom headers to capture
318317

319318
request_headers = {
320319
'X-Capture-This': 'this',
321320
'X-Capture-That': 'that'
322321
}
322+
323323
with tracer.start_active_span('test'):
324324
result = requests.get(testenv["fastapi_server"] + '/', headers=request_headers)
325325

@@ -366,3 +366,53 @@ def test_custom_header_capture(server):
366366
assert ("this" == asgi_span.data["http"]["header"]["X-Capture-This"])
367367
assert ("X-Capture-That" in asgi_span.data["http"]["header"])
368368
assert ("that" == asgi_span.data["http"]["header"]["X-Capture-That"])
369+
370+
371+
def test_response_header_capture(server):
372+
373+
# The background FastAPI server is pre-configured with custom headers to capture
374+
375+
with tracer.start_active_span('test'):
376+
result = requests.get(testenv["fastapi_server"] + '/response_headers')
377+
378+
assert result.status_code == 200
379+
380+
spans = tracer.recorder.queued_spans()
381+
assert len(spans) == 3
382+
383+
span_filter = lambda span: span.n == "sdk" and span.data['sdk']['name'] == 'test'
384+
test_span = get_first_span_by_filter(spans, span_filter)
385+
assert (test_span)
386+
387+
span_filter = lambda span: span.n == "urllib3"
388+
urllib3_span = get_first_span_by_filter(spans, span_filter)
389+
assert (urllib3_span)
390+
391+
span_filter = lambda span: span.n == 'asgi'
392+
asgi_span = get_first_span_by_filter(spans, span_filter)
393+
assert (asgi_span)
394+
395+
assert (test_span.t == urllib3_span.t == asgi_span.t)
396+
assert (asgi_span.p == urllib3_span.s)
397+
assert (urllib3_span.p == test_span.s)
398+
399+
assert "X-INSTANA-T" in result.headers
400+
assert result.headers["X-INSTANA-T"] == asgi_span.t
401+
assert "X-INSTANA-S" in result.headers
402+
assert result.headers["X-INSTANA-S"] == asgi_span.s
403+
assert "X-INSTANA-L" in result.headers
404+
assert result.headers["X-INSTANA-L"] == '1'
405+
assert "Server-Timing" in result.headers
406+
assert result.headers["Server-Timing"] == ("intid;desc=%s" % asgi_span.t)
407+
408+
assert (asgi_span.ec == None)
409+
assert (asgi_span.data['http']['host'] == '127.0.0.1')
410+
assert (asgi_span.data['http']['path'] == '/response_headers')
411+
assert (asgi_span.data['http']['path_tpl'] == '/response_headers')
412+
assert (asgi_span.data['http']['method'] == 'GET')
413+
assert (asgi_span.data['http']['status'] == 200)
414+
assert (asgi_span.data['http']['error'] is None)
415+
assert (asgi_span.data['http']['params'] is None)
416+
417+
assert ("X-Capture-This-Too" in asgi_span.data["http"]["header"])
418+
assert ("this too" == asgi_span.data["http"]["header"]["X-Capture-This-Too"])

0 commit comments

Comments
 (0)