11import api , { trace , context , propagation , Context as OtelContext , ROOT_CONTEXT , Attributes } from "@opentelemetry/api" ;
2- import { Handler } from "aws-lambda" ;
2+ import { Handler , DynamoDBStreamEvent , S3Event } from "aws-lambda" ;
33import { flattenObject } from './utils' ;
44import { Context } from 'aws-lambda' ;
55export * as logger from './logger' ;
@@ -8,29 +8,50 @@ declare const global : {
88 baselimeLambdaFlush : ( ) => Promise < void > ;
99}
1010
11+ type FaasDocument = {
12+ collection : string
13+ operation : string
14+ time : string
15+ name : string
16+ }
17+ let coldstart = true ;
18+
1119export function wrap ( handler : Handler ) {
1220 return async ( event : any , lambda_context : Context ) => {
1321 const tracer = trace . getTracer ( '@baselime/baselime-lambda-wrapper' , '1' ) ;
22+ const service = detectService ( event ) ;
23+ const trigger = triggerToServiceType ( service ) ;
24+ const parent = determinParent ( event , service ) ;
25+ let document : FaasDocument | null = null ;
26+ if ( trigger === 'datasource' ) {
27+ if ( service === 'dynamodb' ) {
28+ document = getDynamodbStreamDocumentAttributes ( event ) ;
29+ }
1430
15- const parent = determinParent ( event ) ;
31+ if ( service === 's3' ) {
32+ document = getS3DocumentAttributes ( event ) ;
33+ }
34+ }
1635 const span = tracer . startSpan ( lambda_context . functionName , {
1736 attributes : flattenObject ( {
1837 event,
1938 context : lambda_context ,
2039 faas : {
2140 execution : lambda_context . awsRequestId ,
22- name : lambda_context . functionName ,
2341 runtime : 'nodejs' ,
42+ trigger,
43+ document,
44+ invoked_by : service ,
2445 id : lambda_context . invokedFunctionArn ,
25-
46+ coldstart ,
2647 } ,
2748 cloud : {
28- account : {
29- id : lambda_context . invokedFunctionArn . split ( ":" ) [ 4 ] ,
30- }
49+ resource_id : lambda_context . invokedFunctionArn ,
50+ account_id : lambda_context . invokedFunctionArn . split ( ":" ) [ 4 ] ,
3151 }
3252 } ) as Attributes ,
3353 } , parent ) ;
54+ coldstart = false ;
3455 const ctx = trace . setSpan ( context . active ( ) , span ) ;
3556
3657 try {
@@ -55,16 +76,56 @@ export function wrap(handler: Handler) {
5576
5677function detectService ( event : any ) {
5778 if ( event . requestContext ?. apiId ) {
58- return "api" ;
79+ return "api-gateway " ;
5980 }
6081
82+ if ( event . requestContext ?. apiId && event . version === "2.0" ) {
83+ return "api-gateway-v2" ;
84+ }
85+
6186 if ( event . Records && event . Records [ 0 ] ?. EventSource === "aws:sns" ) {
6287 return "sns" ;
6388 }
6489
90+ if ( event . Records && event . Records [ 0 ] ?. eventSource === "aws:sqs" ) {
91+ return "sqs" ;
92+ }
93+
94+ if ( event . Records && event . Records [ 0 ] ?. eventSource === "aws:kinesis" ) {
95+ return "kinesis" ;
96+ }
97+
98+ if ( event . Records && event . Records [ 0 ] ?. eventSource === "aws:dynamodb" ) {
99+ return "dynamodb" ;
100+ }
101+
102+ if ( event . Records && event . Records [ 0 ] ?. eventSource === "aws:s3" ) {
103+ return "s3" ;
104+ }
105+
65106 return 'unknown'
66107}
67108
109+ function triggerToServiceType ( service : string ) {
110+ switch ( service ) {
111+ case "api" :
112+ case "api-gateway" :
113+ case "api-gateway-v2" :
114+ case "function-url" :
115+ return "http" ;
116+ case "sns" :
117+ case "sqs" :
118+ case "kinesis" :
119+ case "eventbridge" :
120+ return "pubsub" ;
121+ case "dynamodb" :
122+ case "s3" :
123+ return "datasource"
124+ default :
125+ return "other" ;
126+ }
127+ }
128+
68129const headerGetter = {
69130 keys ( carrier : Object ) : string [ ] {
70131 return Object . keys ( carrier ) ;
@@ -83,10 +144,10 @@ const snsGetter = {
83144 } ,
84145} ;
85146
86- function determinParent ( event : any ) : OtelContext {
147+ function determinParent ( event : any , service : string ) : OtelContext {
87148 let parent : OtelContext | undefined = undefined ;
88149
89- const extractedContext = extractContext ( event ) ;
150+ const extractedContext = extractContext ( event , service ) ;
90151
91152 if ( trace . getSpan ( extractedContext ) ?. spanContext ( ) ) {
92153 return extractedContext ;
@@ -98,9 +159,12 @@ function determinParent(event: any): OtelContext {
98159 return parent ;
99160}
100161
101- function extractContext ( event : any ) {
102- switch ( detectService ( event ) ) {
162+ function extractContext ( event : any , service : string ) {
163+ switch ( service ) {
103164 case "api" :
165+ case "api-gateway" :
166+ case "api-gateway-v2" :
167+ case "function-url" :
104168 const httpHeaders = event . headers || { } ;
105169 return propagation . extract (
106170 api . context . active ( ) ,
@@ -116,3 +180,39 @@ function extractContext(event: any) {
116180 }
117181 return propagation . extract ( api . context . active ( ) , { } , headerGetter ) ;
118182}
183+
184+ const DynamodbEventToDocumentOperations = {
185+ INSERT : 'insert' ,
186+ MODIFY : 'update' ,
187+ REMOVE : 'delete' ,
188+ default : ''
189+ } ;
190+
191+ function getDynamodbStreamDocumentAttributes ( event : DynamoDBStreamEvent ) : FaasDocument {
192+ const unixTime = event ?. Records [ 0 ] ?. dynamodb ?. ApproximateCreationDateTime || Date . now ( ) / 1000 ;
193+ return {
194+ // TODO we could do better for collection (infer from single table design patterns?)
195+ collection : ( event ?. Records [ 0 ] ?. eventSourceARN || '' ) . split ( "/" ) [ 1 ] ,
196+ name : ( event ?. Records [ 0 ] ?. eventSourceARN || '' ) . split ( "/" ) [ 1 ] ,
197+ operation : DynamodbEventToDocumentOperations [ event ?. Records [ 0 ] ?. eventName || "default" ] ,
198+ time : new Date ( unixTime ) . toUTCString ( ) ,
199+ }
200+ }
201+
202+ function getS3DocumentAttributes ( event : S3Event ) : FaasDocument {
203+ let operation = 'unkown' ;
204+
205+ if ( event . Records [ 0 ] . eventName . startsWith ( 'ObjectCreated' ) ) {
206+ operation = 'insert' ;
207+ }
208+
209+ if ( event . Records [ 0 ] . eventName . startsWith ( 'ObjectRemoved' ) ) {
210+ operation = 'delete' ;
211+ }
212+ return {
213+ collection : event . Records [ 0 ] . s3 . bucket . name ,
214+ name : event . Records [ 0 ] . s3 . object . key ,
215+ operation,
216+ time : event . Records [ 0 ] . eventTime ,
217+ }
218+ }
0 commit comments