From f708420fe697c7b1d5a6e80d6d8a8098b84a5d89 Mon Sep 17 00:00:00 2001 From: Michele Mancioppi Date: Tue, 5 May 2020 21:58:07 +0200 Subject: [PATCH] Add support for X-INSTANA-SYNTHETIC --- instana/instrumentation/aiohttp/server.py | 4 ++++ instana/instrumentation/aws/triggers.py | 17 +++++++++++++++++ instana/instrumentation/django/middleware.py | 2 ++ instana/instrumentation/flask/vanilla.py | 2 ++ instana/instrumentation/tornado/server.py | 3 +++ tests/data/lambda/api_gateway_event.json | 3 ++- tests/test_aiohttp.py | 3 ++- tests/test_django.py | 3 ++- tests/test_flask.py | 3 ++- tests/test_lambda.py | 1 + tests/test_tornado_server.py | 3 ++- 11 files changed, 39 insertions(+), 5 deletions(-) diff --git a/instana/instrumentation/aiohttp/server.py b/instana/instrumentation/aiohttp/server.py index 6508ab90..8d53ed61 100644 --- a/instana/instrumentation/aiohttp/server.py +++ b/instana/instrumentation/aiohttp/server.py @@ -37,6 +37,10 @@ async def stan_middleware(request, handler): if custom_header in request.headers: scope.span.set_tag("http.%s" % custom_header, request.headers[custom_header]) + if 'X-INSTANA-SYNTHETIC' in request.headers: + if request.headers['X-INSTANA-SYNTHETIC'] == '1': + scope.span.set_tag('sy', True) + response = await handler(request) if response is not None: diff --git a/instana/instrumentation/aws/triggers.py b/instana/instrumentation/aws/triggers.py index 00cee7a9..e2ce871e 100644 --- a/instana/instrumentation/aws/triggers.py +++ b/instana/instrumentation/aws/triggers.py @@ -93,6 +93,19 @@ def capture_extra_headers(event, span, extra_headers): span.set_tag("http.%s" % custom_header, event["headers"][key]) +def capture_synthetic_header(event, span): + """ + Marks the span as synthetic if the request contains the + `X-INSTANA-SYNTHETIC` header with value `1` + + @param event: the lambda event + @param span: the lambda entry span + @return: None + """ + if event["headers"]["X-INSTANA-SYNTHETIC"] == '1': + span.set_tag('sy', True) + + def enrich_lambda_span(agent, span, event, context): """ Extract the required information about this Lambda run (and the trigger) and store the data @@ -116,6 +129,8 @@ def enrich_lambda_span(agent, span, event, context): span.set_tag('http.path_tpl', event["resource"]) span.set_tag('http.params', read_http_query_params(event)) + capture_synthetic_header(event, span) + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: capture_extra_headers(event, span, agent.extra_headers) @@ -125,6 +140,8 @@ def enrich_lambda_span(agent, span, event, context): span.set_tag('http.url', event["path"]) span.set_tag('http.params', read_http_query_params(event)) + capture_synthetic_header(event, span) + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: capture_extra_headers(event, span, agent.extra_headers) diff --git a/instana/instrumentation/django/middleware.py b/instana/instrumentation/django/middleware.py index 1717935b..0320f123 100644 --- a/instana/instrumentation/django/middleware.py +++ b/instana/instrumentation/django/middleware.py @@ -39,6 +39,8 @@ def process_request(self, request): request.iscope.span.set_tag("http.%s" % custom_header, env[django_header]) request.iscope.span.set_tag(ext.HTTP_METHOD, request.method) + if env('HTTP_X_INSTANA_SYNTHETIC') == '1': + request.iscope.span.set_tag('sy', True) if 'PATH_INFO' in env: request.iscope.span.set_tag(ext.HTTP_URL, env['PATH_INFO']) if 'QUERY_STRING' in env and len(env['QUERY_STRING']): diff --git a/instana/instrumentation/flask/vanilla.py b/instana/instrumentation/flask/vanilla.py index 8e424d94..6763f46c 100644 --- a/instana/instrumentation/flask/vanilla.py +++ b/instana/instrumentation/flask/vanilla.py @@ -33,6 +33,8 @@ def before_request_with_instana(*argv, **kwargs): span.set_tag("http.%s" % custom_header, env[header]) span.set_tag(ext.HTTP_METHOD, flask.request.method) + if env('HTTP_X_INSTANA_SYNTHETIC') == '1': + span.set_tag('sy', True) if 'PATH_INFO' in env: span.set_tag(ext.HTTP_URL, env['PATH_INFO']) if 'QUERY_STRING' in env and len(env['QUERY_STRING']): diff --git a/instana/instrumentation/tornado/server.py b/instana/instrumentation/tornado/server.py index 0c65968a..177f86c8 100644 --- a/instana/instrumentation/tornado/server.py +++ b/instana/instrumentation/tornado/server.py @@ -44,6 +44,9 @@ def execute_with_instana(wrapped, instance, argv, kwargs): if custom_header in instance.request.headers: scope.span.set_tag("http.%s" % custom_header, instance.request.headers[custom_header]) + if instance.request.headers['X-INSTANA-SYNTHETIC'] == '1': + scope.span.set_tag('sy', True) + setattr(instance.request, "_instana", scope) # Set the context response headers now because tornado doesn't give us a better option to do so diff --git a/tests/data/lambda/api_gateway_event.json b/tests/data/lambda/api_gateway_event.json index 623d3dd2..291e8032 100644 --- a/tests/data/lambda/api_gateway_event.json +++ b/tests/data/lambda/api_gateway_event.json @@ -39,7 +39,8 @@ "X-Forwarded-Proto": "https", "X-Instana-T": "d5cb361b256413a9", "X-Instana-S": "0901d8ae4fbf1529", - "X-Instana-L": "1" + "X-Instana-L": "1", + "X-Instana-Synthetic": "1" }, "multiValueHeaders": { "Accept": [ diff --git a/tests/test_aiohttp.py b/tests/test_aiohttp.py index 8759a0df..78cab60c 100644 --- a/tests/test_aiohttp.py +++ b/tests/test_aiohttp.py @@ -34,7 +34,7 @@ def test_client_get(self): async def test(): with async_tracer.start_active_span('test'): async with aiohttp.ClientSession() as session: - return await self.fetch(session, testenv["wsgi_server"] + "/") + return await self.fetch(session, testenv["wsgi_server"] + "/", headers={'X-INSTANA-SYNTHETIC': '1'}) response = self.loop.run_until_complete(test()) @@ -65,6 +65,7 @@ async def test(): self.assertEqual(200, aiohttp_span.data["http"]["status"]) self.assertEqual(testenv["wsgi_server"] + "/", aiohttp_span.data["http"]["url"]) self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertEqual(True, aiohttp_span.data["sy"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) diff --git a/tests/test_django.py b/tests/test_django.py index 1b5770bc..701d2745 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -25,7 +25,7 @@ def tearDown(self): def test_basic_request(self): with tracer.start_active_span('test'): - response = self.http.request('GET', self.live_server_url + '/') + response = self.http.request('GET', self.live_server_url + '/', headers={'X-INSTANA-SYNTHETIC': '1'}) assert response assert_equals(200, response.status) @@ -67,6 +67,7 @@ def test_basic_request(self): assert_equals('/', django_span.data["http"]["url"]) assert_equals('GET', django_span.data["http"]["method"]) assert_equals(200, django_span.data["http"]["status"]) + assert_equals(True, django_span.data["sy"]) assert django_span.stack assert_equals(2, len(django_span.stack)) diff --git a/tests/test_flask.py b/tests/test_flask.py index 47d6a7d1..e9b4321f 100644 --- a/tests/test_flask.py +++ b/tests/test_flask.py @@ -29,7 +29,7 @@ def test_vanilla_requests(self): def test_get_request(self): with tracer.start_active_span('test'): - response = self.http.request('GET', testenv["wsgi_server"] + '/') + response = self.http.request('GET', testenv["wsgi_server"] + '/', headers={'X-INSTANA-SYNTHETIC': '1'}) spans = self.recorder.queued_spans() self.assertEqual(3, len(spans)) @@ -78,6 +78,7 @@ def test_get_request(self): self.assertEqual('GET', wsgi_span.data["http"]["method"]) self.assertEqual(200, wsgi_span.data["http"]["status"]) self.assertIsNone(wsgi_span.data["http"]["error"]) + self.assertEqual(True, wsgi_span.data["sy"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) diff --git a/tests/test_lambda.py b/tests/test_lambda.py index 0ea1214f..07715f6d 100644 --- a/tests/test_lambda.py +++ b/tests/test_lambda.py @@ -150,6 +150,7 @@ def test_api_gateway_trigger_tracing(self): self.assertEqual('POST', span.data['http']['method']) self.assertEqual('/path/to/resource', span.data['http']['url']) self.assertEqual('/{proxy+}', span.data['http']['path_tpl']) + self.assertEqual(True, span.data['sy']) if sys.version[:3] == '2.7': self.assertEqual(u"foo=[u'bar']", span.data['http']['params']) else: diff --git a/tests/test_tornado_server.py b/tests/test_tornado_server.py index 60c58cb0..43c86f7c 100644 --- a/tests/test_tornado_server.py +++ b/tests/test_tornado_server.py @@ -47,7 +47,7 @@ def test_get(self): async def test(): with async_tracer.start_active_span('test'): async with aiohttp.ClientSession() as session: - return await self.fetch(session, testenv["tornado_server"] + "/") + return await self.fetch(session, testenv["tornado_server"] + "/", headers={'X-INSTANA-SYNTHETIC': '1'}) response = tornado.ioloop.IOLoop.current().run_sync(test) @@ -82,6 +82,7 @@ async def test(): self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data["http"]["url"]) self.assertIsNone(tornado_span.data["http"]["params"]) self.assertEqual("GET", tornado_span.data["http"]["method"]) + self.assertEqual(True, tornado_span.data["sy"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1)