Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions instana/instrumentation/aws/lambda_inst.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""
import sys
import wrapt
import opentracing.ext.tags as ext

from ...log import logger
from ...singletons import env_is_aws_lambda
Expand Down Expand Up @@ -35,6 +36,11 @@ def lambda_handler_with_instana(wrapped, instance, args, kwargs):
result['headers']['Server-Timing'] = server_timing_value
elif 'multiValueHeaders' in result:
result['multiValueHeaders']['Server-Timing'] = [server_timing_value]
if 'statusCode' in result and result.get('statusCode'):
status_code = int(result['statusCode'])
scope.span.set_tag(ext.HTTP_STATUS_CODE, status_code)
if 500 <= status_code:
scope.span.log_exception(f'HTTP status {status_code}')
except Exception as exc:
if scope.span:
exc = traceback.format_exc()
Expand Down
123 changes: 81 additions & 42 deletions tests/platforms/test_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ def my_lambda_handler(event, context):
module_name, function_name = get_lambda_handler_or_default()
wrapt.wrap_function_wrapper(module_name, function_name, lambda_handler_with_instana)

def my_errored_lambda_handler(event, context):
return {
'statusCode': 500,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps({'site': 'wikipedia.org', 'response': 500})
}

os.environ["LAMBDA_HANDLER"] = "tests.platforms.test_lambda.my_errored_lambda_handler"
module_name, function_name = get_lambda_handler_or_default()
wrapt.wrap_function_wrapper(module_name, function_name, lambda_handler_with_instana)

class TestLambda(unittest.TestCase):
def __init__(self, methodName='runTest'):
Expand Down Expand Up @@ -230,6 +240,7 @@ def test_custom_service_name(self):

self.assertEqual('aws:api.gateway', span.data['lambda']['trigger'])
self.assertEqual('POST', span.data['http']['method'])
self.assertEqual(200, span.data['http']['status'])
self.assertEqual('/path/to/resource', span.data['http']['url'])
self.assertEqual('/{proxy+}', span.data['http']['path_tpl'])
self.assertEqual("foo=['bar']", span.data['http']['params'])
Expand Down Expand Up @@ -293,6 +304,7 @@ def test_api_gateway_trigger_tracing(self):

self.assertEqual('aws:api.gateway', span.data['lambda']['trigger'])
self.assertEqual('POST', span.data['http']['method'])
self.assertEqual(200, span.data['http']['status'])
self.assertEqual('/path/to/resource', span.data['http']['url'])
self.assertEqual('/{proxy+}', span.data['http']['path_tpl'])
self.assertEqual("foo=['bar']", span.data['http']['params'])
Expand All @@ -307,58 +319,35 @@ def test_api_gateway_v2_trigger_tracing(self):
# figure out the original (the users') Lambda Handler and execute it.
# The original Lambda handler is set in os.environ["LAMBDA_HANDLER"]
result = lambda_handler(event, self.context)

assert isinstance(result, dict)
assert 'headers' in result
assert 'Server-Timing' in result['headers']

time.sleep(1)
payload = self.agent.collector.prepare_payload()
self.__validate_result_and_payload_for_gateway_v2_trace(result, payload)

self.assertTrue("metrics" in payload)
self.assertTrue("spans" in payload)
self.assertEqual(2, len(payload.keys()))

self.assertTrue(isinstance(payload['metrics']['plugins'], list))
self.assertTrue(len(payload['metrics']['plugins']) == 1)
plugin_data = payload['metrics']['plugins'][0]

self.assertEqual('com.instana.plugin.aws.lambda', plugin_data['name'])
self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', plugin_data['entityId'])

self.assertEqual(1, len(payload['spans']))

self.assertEqual(200, result['statusCode'])
span = payload['spans'][0]
self.assertEqual('aws.lambda.entry', span.n)
self.assertEqual('0000000000001234', span.t)
self.assertIsNotNone(span.s)
self.assertEqual('0000000000004567', span.p)
self.assertIsNotNone(span.ts)
self.assertIsNotNone(span.d)
self.assertIsNone(span.ec)
self.assertIsNone(span.data['lambda']['error'])
self.assertEqual(200, span.data['http']['status'])

server_timing_value = "intid;desc=%s" % span.t
assert result['headers']['Server-Timing'] == server_timing_value

self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'},
span.f)
def test_api_gateway_v2_trigger_errored_tracing(self):

self.assertTrue(span.sy)
with open(self.pwd + '/../data/lambda/api_gateway_v2_event.json', 'r') as json_file:
event = json.load(json_file)

self.assertIsNone(span.ec)
self.assertIsNone(span.data['lambda']['error'])
os.environ["LAMBDA_HANDLER"] = "tests.platforms.test_lambda.my_errored_lambda_handler"
self.create_agent_and_setup_tracer()

self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', span.data['lambda']['arn'])
self.assertEqual(None, span.data['lambda']['alias'])
self.assertEqual('python', span.data['lambda']['runtime'])
self.assertEqual('TestPython', span.data['lambda']['functionName'])
self.assertEqual('1', span.data['lambda']['functionVersion'])
self.assertIsNone(span.data['service'])
result = lambda_handler(event, self.context)
time.sleep(1)
payload = self.agent.collector.prepare_payload()
self.__validate_result_and_payload_for_gateway_v2_trace(result, payload)

self.assertEqual('aws:api.gateway', span.data['lambda']['trigger'])
self.assertEqual('POST', span.data['http']['method'])
self.assertEqual('/my/path', span.data['http']['url'])
self.assertEqual('/my/{resource}', span.data['http']['path_tpl'])
self.assertEqual("secret=key&q=term", span.data['http']['params'])
self.assertEqual(500, result['statusCode'])
span = payload['spans'][0]
self.assertEqual(1, span.ec)
self.assertEqual('HTTP status 500', span.data['lambda']['error'])
self.assertEqual(500, span.data['http']['status'])


def test_application_lb_trigger_tracing(self):
Expand Down Expand Up @@ -420,6 +409,7 @@ def test_application_lb_trigger_tracing(self):

self.assertEqual('aws:api.gateway', span.data['lambda']['trigger'])
self.assertEqual('POST', span.data['http']['method'])
self.assertEqual(200, span.data['http']['status'])
self.assertEqual('/path/to/resource', span.data['http']['url'])
self.assertEqual("foo=['bar']", span.data['http']['params'])

Expand Down Expand Up @@ -723,3 +713,52 @@ def test_agent_custom_log_level(self):
os.environ['INSTANA_LOG_LEVEL'] = "eRror"
self.create_agent_and_setup_tracer()
assert self.agent.options.log_level == logging.ERROR

def __validate_result_and_payload_for_gateway_v2_trace(self, result, payload):
self.assertIsInstance(result, dict)
self.assertIn('headers', result)
self.assertIn('Server-Timing', result['headers'])
self.assertIn('statusCode', result)

self.assertTrue("metrics" in payload)
self.assertTrue("spans" in payload)
self.assertEqual(2, len(payload.keys()))

self.assertTrue(isinstance(payload['metrics']['plugins'], list))
self.assertTrue(len(payload['metrics']['plugins']) == 1)
plugin_data = payload['metrics']['plugins'][0]

self.assertEqual('com.instana.plugin.aws.lambda', plugin_data['name'])
self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', plugin_data['entityId'])

self.assertEqual(1, len(payload['spans']))

span = payload['spans'][0]
self.assertEqual('aws.lambda.entry', span.n)
self.assertEqual('0000000000001234', span.t)
self.assertIsNotNone(span.s)
self.assertEqual('0000000000004567', span.p)
self.assertIsNotNone(span.ts)
self.assertIsNotNone(span.d)

server_timing_value = "intid;desc=%s" % span.t
assert result['headers']['Server-Timing'] == server_timing_value

self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'},
span.f)

self.assertTrue(span.sy)


self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', span.data['lambda']['arn'])
self.assertEqual(None, span.data['lambda']['alias'])
self.assertEqual('python', span.data['lambda']['runtime'])
self.assertEqual('TestPython', span.data['lambda']['functionName'])
self.assertEqual('1', span.data['lambda']['functionVersion'])
self.assertIsNone(span.data['service'])

self.assertEqual('aws:api.gateway', span.data['lambda']['trigger'])
self.assertEqual('POST', span.data['http']['method'])
self.assertEqual('/my/path', span.data['http']['url'])
self.assertEqual('/my/{resource}', span.data['http']['path_tpl'])
self.assertEqual("secret=key&q=term", span.data['http']['params'])