diff --git a/iopipe/contrib/eventinfo/event_types.py b/iopipe/contrib/eventinfo/event_types.py index 33cbd610..3095000e 100644 --- a/iopipe/contrib/eventinfo/event_types.py +++ b/iopipe/contrib/eventinfo/event_types.py @@ -5,6 +5,7 @@ class EventType(object): keys = [] exclude_keys = [] required_keys = [] + source = None def __init__(self, event): self.event = event @@ -21,10 +22,16 @@ def collect(self): return collect_all_keys(self.event, '@iopipe/event-info.%s' % self.type, self.exclude_keys) event_info = {} for key in self.keys: - value = get_value(self.event, key) + if isinstance(key, tuple): + old_key, new_key = key + else: + old_key = new_key = key + value = get_value(self.event, old_key) if value is not None: - event_info['@iopipe/event-info.%s.%s' % (self.type, key)] = value + event_info['@iopipe/event-info.%s.%s' % (self.type, new_key)] = value event_info['@iopipe/event-info.eventType'] = self.type + if self.source: + event_info['@iopipe/event-info.eventType.source'] = self.source return event_info @@ -152,6 +159,25 @@ def has_required_keys(self): return super(Scheduled, self).has_required_keys() and get_value(self.event, 'source') == 'aws.events' +class ServerlessLambda(EventType): + type = 'apiGateway' + source = 'slsIntegrationLambda' + keys = [ + ('headers.["X-Amz-Cf-Id"]', 'headers.X-Amz-Cf-Id'), + ('headers.["X-Amzn-Trace-Id"]', 'headers.X-Amzn-Trace-Id'), + ('identity.accountId', 'requestContext.accountId'), + ('identity.userAgent', 'requestContext.identity.userAgent'), + ('method', 'httpMethod'), + ('method', 'requestContext.httpMethod'), + ('stage', 'requestContext.stage'), + ] + required_keys = [ + 'identity.userAgent', + 'identity.sourceIp', + 'identity.accountId', + ] + + class SNS(EventType): type = 'sns' keys = [ @@ -177,7 +203,7 @@ def has_required_keys(self): get_value(self.event, 'Records[0].eventSource') == 'aws:sns' -EVENT_TYPES = [AlexaSkill, ApiGateway, CloudFront, Firehose, Kinesis, S3, Scheduled, SNS] +EVENT_TYPES = [AlexaSkill, ApiGateway, CloudFront, Firehose, Kinesis, S3, Scheduled, ServerlessLambda, SNS] def metrics_for_event_type(event, context): diff --git a/iopipe/contrib/eventinfo/plugin.py b/iopipe/contrib/eventinfo/plugin.py index caa9882e..7d3a8b15 100644 --- a/iopipe/contrib/eventinfo/plugin.py +++ b/iopipe/contrib/eventinfo/plugin.py @@ -5,7 +5,7 @@ class EventInfoPlugin(Plugin): name = 'event-info' - version = '1.1.0' + version = '1.2.0' homepage = 'https://github.com/iopipe/iopipe-python#event-info-plugin' enabled = True diff --git a/tests/contrib/eventinfo/conftest.py b/tests/contrib/eventinfo/conftest.py index 6f6e625e..bf5d6a5b 100644 --- a/tests/contrib/eventinfo/conftest.py +++ b/tests/contrib/eventinfo/conftest.py @@ -51,3 +51,8 @@ def event_kinesis(): @pytest.fixture def event_scheduled(): return _load_event('scheduled') + + +@pytest.fixture +def event_serverless_lambda(): + return _load_event('serverless_lambda') diff --git a/tests/contrib/eventinfo/events/serverless_lambda.json b/tests/contrib/eventinfo/events/serverless_lambda.json new file mode 100644 index 00000000..ad6b3223 --- /dev/null +++ b/tests/contrib/eventinfo/events/serverless_lambda.json @@ -0,0 +1,47 @@ +{ + "body": {}, + "method": "GET", + "principalId": "1234", + "stage": "dev", + "cognitoPoolClaims": { + "sub": "" + }, + "enhancedAuthContext": {}, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en-GB,en-US;q=0.8,en;q=0.6,zh-CN;q=0.4", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "GB", + "Host": "ec5ycylws8.execute-api.us-east-1.amazonaws.com", + "upgrade-insecure-requests": "1", + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", + "Via": "2.0 f165ce34daf8c0da182681179e863c24.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "l06CAg2QsrALeQcLAUSxGXbm8lgMoMIhR2AjKa4AiKuaVnnGsOFy5g==", + "X-Amzn-Trace-Id": "Root=1-5970ef3e249c0321b2eef14aa513ae", + "X-Forwarded-For": "94.117.120.169, 116.132.62.73", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "query": {}, + "path": {}, + "identity": { + "cognitoIdentityPoolId": "", + "accountId": "1234", + "cognitoIdentityId": "", + "caller": "", + "apiKey": "", + "sourceIp": "94.197.120.169", + "accessKey": "", + "cognitoAuthenticationType": "", + "cognitoAuthenticationProvider": "", + "userArn": "", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", + "user": "" + }, + "stageVariables": {} +} diff --git a/tests/contrib/eventinfo/test_event_types.py b/tests/contrib/eventinfo/test_event_types.py index 90377fcf..ca7f2d0f 100644 --- a/tests/contrib/eventinfo/test_event_types.py +++ b/tests/contrib/eventinfo/test_event_types.py @@ -1,7 +1,8 @@ from iopipe.contrib.eventinfo import event_types as et +from iopipe.contrib.eventinfo.util import get_value -def test__event_Types__alexa_skill(event_alexa_skill): +def test__event_types__alexa_skill(event_alexa_skill): event = et.AlexaSkill(event_alexa_skill) assert event.has_required_keys() is True @@ -11,7 +12,7 @@ def test__event_Types__alexa_skill(event_alexa_skill): assert len(list(event_info.keys())) == 31 -def test__event_Types__apigw(event_apigw): +def test__event_types__apigw(event_apigw): event = et.ApiGateway(event_apigw) assert event.has_required_keys() is True @@ -22,7 +23,7 @@ def test__event_Types__apigw(event_apigw): assert list(event_info.keys()).sort() == expected_keys.sort() -def test__event_Types__cloudfront(event_cloudfront): +def test__event_types__cloudfront(event_cloudfront): event = et.CloudFront(event_cloudfront) assert event.has_required_keys() is True @@ -53,3 +54,22 @@ def test__event_types__scheduled(event_scheduled): expected_keys = ['@iopipe/event-info.eventType'] + ['@iopipe/event-info.scheduled.%s' % key for key in event.keys] assert list(event_info.keys()).sort() == expected_keys.sort() + + +def test__event_types__serverless_lambda(event_serverless_lambda): + event = et.ServerlessLambda(event_serverless_lambda) + assert event.has_required_keys() is True + + event_info = event.collect() + assert event_info != {} + + expected_keys = [ + '@iopipe/event-info.eventType', + '@iopipe/event-info.eventType.source', + ] + ['@iopipe/event-info.apiGateway.%s' % key[1] for key in event.keys] + assert list(event_info.keys()).sort() == expected_keys.sort() + assert all([ + get_value(event_serverless_lambda, old_key) == event_info['@iopipe/event-info.apiGateway.%s' % new_key] + for old_key, new_key in event.keys + ]) + assert event_info['@iopipe/event-info.eventType.source'] == event.source