1
1
import { APIGatewayProxyEvent , APIGatewayProxyResult , Context } from 'aws-lambda' ;
2
- import { Metrics } from '@aws-lambda-powertools/metrics ' ;
3
- import { Logger } from '@aws-lambda-powertools/logger ' ;
4
- import { Tracer } from '@aws-lambda-powertools/tracer ' ;
5
- import { DocumentClient } from 'aws-sdk/clients /dynamodb' ;
6
-
7
- // Create the PowerTools clients
8
- const metrics = new Metrics ( ) ;
9
- const logger = new Logger ( ) ;
10
- const tracer = new Tracer ( ) ;
11
-
12
- // Create DynamoDB DocumentClient and patch it for tracing
13
- const docClient = tracer . captureAWSClient ( new DocumentClient ( ) ) ;
14
-
15
- // Get the DynamoDB table name from environment variables
16
- const tableName = process . env . SAMPLE_TABLE ;
2
+ import { tableName } from './common/constants ' ;
3
+ import { logger , tracer , metrics } from './common/powertools ' ;
4
+ import { LambdaInterface } from '@aws-lambda-powertools/commons ' ;
5
+ import { docClient } from './common /dynamodb-client ' ;
6
+ import { GetItemCommand } from '@aws-sdk/lib-dynamodb' ;
7
+ import got from 'got' ;
8
+
9
+ /*
10
+ *
11
+ * This example uses the Method decorator instrumentation.
12
+ * Use TypeScript method decorators if you prefer writing your business logic using TypeScript Classes.
13
+ * If you aren’t using Classes, this requires the most significant refactoring.
14
+ * Find more Information in the docs: https://awslabs.github.io/aws-lambda-powertools-typescript/
15
+ *
16
+ */
17
17
18
18
/**
19
19
*
@@ -25,72 +25,89 @@ const tableName = process.env.SAMPLE_TABLE;
25
25
*
26
26
*/
27
27
28
- export const getByIdHandler = async ( event : APIGatewayProxyEvent , context : Context ) : Promise < APIGatewayProxyResult > => {
29
- if ( event . httpMethod !== 'GET' ) {
30
- throw new Error ( `getById only accepts GET method, you tried: ${ event . httpMethod } ` ) ;
28
+ class Lambda implements LambdaInterface {
29
+
30
+ @tracer . captureMethod ( )
31
+ public async getUuid ( ) : Promise < string > {
32
+ // Request a sample random uuid from a webservice
33
+ const res = await got ( 'https://httpbin.org/uuid' ) ;
34
+
35
+ return JSON . parse ( res . body ) . uuid ;
31
36
}
32
- // Tracer: Get facade segment created by AWS Lambda
33
- const segment = tracer . getSegment ( ) ;
34
-
35
- // Tracer: Create subsegment for the function & set it as active
36
- const handlerSegment = segment . addNewSubsegment ( `## ${ process . env . _HANDLER } ` ) ;
37
- tracer . setSegment ( handlerSegment ) ;
38
-
39
- // Tracer: Annotate the subsegment with the cold start & serviceName
40
- tracer . annotateColdStart ( ) ;
41
- tracer . addServiceNameAnnotation ( ) ;
42
-
43
- // Tracer: Add annotation for the awsRequestId
44
- tracer . putAnnotation ( 'awsRequestId' , context . awsRequestId ) ;
45
-
46
- // Metrics: Capture cold start metrics
47
- metrics . captureColdStartMetric ( ) ;
48
-
49
- // Logger: Add persistent attributes to each log statement
50
- logger . addPersistentLogAttributes ( {
51
- awsRequestId : context . awsRequestId ,
52
- } ) ;
53
-
54
- // Get the item from the table
55
- // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#get-property
56
- let response ;
57
- try {
58
- if ( ! tableName ) {
59
- throw new Error ( 'SAMPLE_TABLE environment variable is not set' ) ;
60
- }
61
- if ( ! event . pathParameters ) {
62
- throw new Error ( 'event does not contain pathParameters' ) ;
63
- }
64
- if ( ! event . pathParameters . id ) {
65
- throw new Error ( 'PathParameter id is missing' ) ;
37
+
38
+ @tracer . captureLambdaHandler ( { captureResponse : false } ) // by default the tracer would add the response as metadata on the segment, but there is a chance to hit the 64kb segment size limit. Therefore set captureResponse: false
39
+ @logger . injectLambdaContext ( { logEvent : true } )
40
+ @metrics . logMetrics ( { throwOnEmptyMetrics : false , captureColdStartMetric : true } )
41
+ public async handler ( event : APIGatewayProxyEvent , context : Context ) : Promise < APIGatewayProxyResult > {
42
+
43
+ if ( event . httpMethod !== 'GET' ) {
44
+ throw new Error ( `getById only accepts GET method, you tried: ${ event . httpMethod } ` ) ;
66
45
}
67
46
68
- const data = await docClient . get ( {
69
- TableName : tableName ,
70
- Key : { id : event . pathParameters . id } ,
71
- } ) . promise ( ) ;
72
- const item = data . Item ;
73
- response = {
74
- statusCode : 200 ,
75
- body : JSON . stringify ( item )
76
- } ;
77
- } catch ( err ) {
78
- tracer . addErrorAsMetadata ( err as Error ) ;
79
- logger . error ( 'Error reading from table. ' + err ) ;
80
- response = {
81
- statusCode : 500 ,
82
- body : JSON . stringify ( { 'error' : 'Error reading from table.' } )
83
- } ;
84
- }
47
+ // Tracer: Add awsRequestId as annotation
48
+ tracer . putAnnotation ( 'awsRequestId' , context . awsRequestId ) ;
49
+
50
+ // Logger: Append awsRequestId to each log statement
51
+ logger . appendKeys ( {
52
+ awsRequestId : context . awsRequestId ,
53
+ } ) ;
54
+
55
+ // Call the getUuid function
56
+ const uuid = await this . getUuid ( ) ;
57
+
58
+ // Logger: Append uuid to each log statement
59
+ logger . appendKeys ( { uuid } ) ;
60
+
61
+ // Tracer: Add uuid as annotation
62
+ tracer . putAnnotation ( 'uuid' , uuid ) ;
63
+
64
+ // Metrics: Add uuid as metadata
65
+ metrics . addMetadata ( 'uuid' , uuid ) ;
66
+
67
+ // Define response object
68
+ let response ;
69
+
70
+ // Get the item from the table
71
+ // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#get-property
72
+ try {
73
+ if ( ! tableName ) {
74
+ throw new Error ( 'SAMPLE_TABLE environment variable is not set' ) ;
75
+ }
76
+ if ( ! event . pathParameters ) {
77
+ throw new Error ( 'event does not contain pathParameters' ) ;
78
+ }
79
+ if ( ! event . pathParameters . id ) {
80
+ throw new Error ( 'PathParameter id is missing' ) ;
81
+ }
82
+ const data = await docClient . send ( new GetItemCommand ( {
83
+ TableName : tableName ,
84
+ Key : { id :
85
+ {
86
+ S : event . pathParameters . id
87
+ }
88
+ } ,
89
+ } ) ) ;
90
+ const item = data . Item ;
91
+ response = {
92
+ statusCode : 200 ,
93
+ body : JSON . stringify ( item )
94
+ } ;
95
+ } catch ( err ) {
96
+ tracer . addErrorAsMetadata ( err as Error ) ;
97
+ logger . error ( 'Error reading from table. ' + err ) ;
98
+ response = {
99
+ statusCode : 500 ,
100
+ body : JSON . stringify ( { 'error' : 'Error reading from table.' } )
101
+ } ;
102
+ }
85
103
86
- // Tracer: Close subsegment (the AWS Lambda one is closed automatically)
87
- handlerSegment . close ( ) ; // (## index.handler)
104
+ // All log statements are written to CloudWatch
105
+ logger . info ( `response from: ${ event . path } statusCode: ${ response . statusCode } body: ${ response . body } ` ) ;
88
106
89
- // Tracer: Set the facade segment as active again (the one created by AWS Lambda)
90
- tracer . setSegment ( segment ) ;
107
+ return response ;
108
+ }
91
109
92
- // All log statements are written to CloudWatch
93
- logger . info ( `response from: ${ event . path } statusCode: ${ response . statusCode } body: ${ response . body } ` ) ;
110
+ }
94
111
95
- return response ;
96
- } ;
112
+ const handlerClass = new Lambda ( ) ;
113
+ export const handler = handlerClass . handler . bind ( handlerClass ) ;
0 commit comments