import { Context , APIGatewayEvent , APIGatewayProxyEventV2 , ALBEvent , CloudWatchLogsEvent , ScheduledEvent , CloudFrontRequestEvent , DynamoDBStreamEvent , KinesisStreamEvent , S3Event , SNSEvent , SQSEvent , } from "aws-lambda" ; import * as eventType from "../utils/event-type-guards" ; import { logError } from "../utils" ; import { gunzipSync } from "zlib" ; function isHTTPTriggerEvent ( eventSource ) { return eventSource === "api-gateway" || eventSource === "application-load-balancer" ; } function getAWSPartitionByRegion ( region ) { if ( region . startsWith ( "us-gov-" ) ) { return "aws-us-gov" ; } else if ( region . startsWith ( "cn-" ) ) { return "aws-cn" ; } else { return "aws" ; } } function extractAPIGatewayRequestContext ( event ) { return event . requestContext ; } function extractCloudFrontRequestEventDistributionId ( event ) { return event . Records [ 0 ] . cf . config . distributionId ; } function extractCloudWatchLogsEventDecodedLogs ( event ) { const buffer = Buffer . from ( event . awslogs . data , "base64" ) ; const decompressed = gunzipSync ( buffer ) . toString ( ) ; return JSON . parse ( decompressed ) ; } function extractALBEventARN ( event ) { return event . requestContext . elb . targetGroupArn ; } function extractCloudWatchEventARN ( event ) { return event . resources [ 0 ] ; } function extractDynamoDBStreamEventARN ( event ) { return event . Records [ 0 ] . eventSourceARN ; } function extractKinesisStreamEventARN ( event ) { return event . Records [ 0 ] . eventSourceARN ; } function extractS3EventARN ( event ) { return event . Records [ 0 ] . s3 . bucket . arn ; } function extractSNSEventARN ( event ) { return event . Records [ 0 ] . Sns . TopicArn ; } function extractSQSEventARN ( event ) { return event . Records [ 0 ] . eventSourceARN ; } /**
 * parseEventSource parses the triggering event to determine the source
 * Possible Returns:
 * api-gateway | application-load-balancer | cloudwatch-logs |
 * cloudwatch-events | cloudfront | dynamodb | kinesis | s3 | sns | sqs
 */ export function parseEventSource ( event ) { let eventSource ; if ( eventType . isAPIGatewayEvent ( event ) || eventType . isAPIGatewayEventV2 ( event ) ) { eventSource = "api-gateway" ; } if ( eventType . isALBEvent ( event ) ) { eventSource = "application-load-balancer" ; } if ( eventType . isCloudWatchLogsEvent ( event ) ) { eventSource = "cloudwatch-logs" ; } if ( eventType . isCloudWatchEvent ( event ) ) { eventSource = "cloudwatch-events" ; } if ( eventType . isCloudFrontRequestEvent ( event ) ) { eventSource = "cloudfront" ; } if ( eventType . isDynamoDBStreamEvent ( event ) ) { eventSource = "dynamodb" ; } if ( eventType . isKinesisStreamEvent ( event ) ) { eventSource = "kinesis" ; } if ( eventType . isS3Event ( event ) ) { eventSource = "s3" ; } if ( eventType . isSNSEvent ( event ) ) { eventSource = "sns" ; } if ( eventType . isSQSEvent ( event ) ) { eventSource = "sqs" ; } return eventSource ; } /**
 * parseEventSourceARN parses the triggering event to determine the event source's
 * ARN if available. Otherwise we stitch together the ARN
 */ export function parseEventSourceARN ( source , event , context ) { const splitFunctionArn = context . invokedFunctionArn . split ( ":" ) ; const region = splitFunctionArn [ 3 ] ; const accountId = splitFunctionArn [ 4 ] ; const awsARN = getAWSPartitionByRegion ( region ) ; let eventSourceARN ; if ( source === "s3" ) { eventSourceARN = extractS3EventARN ( event ) ; } if ( source === "sns" ) { eventSourceARN = extractSNSEventARN ( event ) ; } if ( source === "sqs" ) { eventSourceARN = extractSQSEventARN ( event ) ; } if ( source === "cloudfront" ) { const distributionId = extractCloudFrontRequestEventDistributionId ( event ) ; eventSourceARN = `arn:${ awsARN }:cloudfront::${ accountId }:distribution/${ distributionId }` ; } if ( source === "api-gateway" ) { const requestContext = extractAPIGatewayRequestContext ( event ) ; eventSourceARN = `arn:${ awsARN }:apigateway:${ region }::/restapis/${ requestContext . apiId }/stages/${ requestContext . stage }` ; } if ( source === "application-load-balancer" ) { eventSourceARN = extractALBEventARN ( event ) ; } if ( source === "cloudwatch-logs" ) { const logs = extractCloudWatchLogsEventDecodedLogs ( event ) ; eventSourceARN = `arn:${ awsARN }:logs:${ region }:${ accountId }:log-group:${ logs . logGroup }` ; } if ( source === "cloudwatch-events" ) { eventSourceARN = extractCloudWatchEventARN ( event ) ; } if ( source === "dynamodb" ) { eventSourceARN = extractDynamoDBStreamEventARN ( event ) ; } if ( source === "kinesis" ) { eventSourceARN = extractKinesisStreamEventARN ( event ) ; } return eventSourceARN ; } /**
 * extractHTTPTags extracts HTTP facet tags from the triggering event
 */ function extractHTTPTags ( event ) { const httpTags = { } ; if ( eventType . isAPIGatewayEvent ( event ) ) { const requestContext = event . requestContext ; if ( requestContext . domainName ) { httpTags [ "http.url" ] = requestContext . domainName ; } httpTags [ "http.url_details.path" ] = requestContext . path ; httpTags [ "http.method" ] = requestContext . httpMethod ; if ( event . headers ?. Referer ) { httpTags [ "http.referer" ] = event . headers . Referer ; } return httpTags ; } if ( eventType . isAPIGatewayEventV2 ( event ) ) { const requestContext = event . requestContext ; httpTags [ "http.url" ] = requestContext . domainName ; httpTags [ "http.url_details.path" ] = requestContext . http . path ; httpTags [ "http.method" ] = requestContext . http . method ; if ( event . headers ?. Referer ) { httpTags [ "http.referer" ] = event . headers . Referer ; } return httpTags ; } if ( eventType . isALBEvent ( event ) ) { httpTags [ "http.url_details.path" ] = event . path ; httpTags [ "http.method" ] = event . httpMethod ; if ( event . headers && event . headers . Referer ) { httpTags [ "http.referer" ] = event . headers . Referer ; } return httpTags ; } } /**
 * extractTriggerTags parses the trigger event object for tags to be added to the span metadata
 */ export function extractTriggerTags ( event , context ) { let triggerTags = { } ; const eventSource = parseEventSource ( event ) ; if ( eventSource ) { triggerTags [ "function_trigger.event_source" ] = eventSource ; let eventSourceARN ; try { eventSourceARN = parseEventSourceARN ( eventSource , event , context ) ; } catch ( error ) { logError ( `failed to extract ${ eventSource } arn from the event` , { error } ) ; } if ( eventSourceARN ) { triggerTags [ "function_trigger.event_source_arn" ] = eventSourceARN ; } } if ( isHTTPTriggerEvent ( eventSource ) ) { try { triggerTags = { ... triggerTags , ... extractHTTPTags ( event ) } ; } catch ( error ) { logError ( `failed to extract http tags from ${ eventSource } event` ) ; } } return triggerTags ; } /**
 * extractHTTPStatusCode extracts a status code from the response if the Lambda was triggered
 * by API Gateway or ALB
 */ export function extractHTTPStatusCodeTag ( triggerTags , result ) { let eventSource ; triggerTags ? ( eventSource = triggerTags [ "function_trigger.event_source" ] ) : ( eventSource = undefined ) ; if ( ! isHTTPTriggerEvent ( eventSource ) ) { return ; } const resultStatusCode = result ?. statusCode ; if ( result === undefined ) { return "502" ; } else if ( resultStatusCode ) { if ( typeof resultStatusCode === "number" ) { return resultStatusCode . toString ( ) ; } } else { return "200" ; } }