Skip to content

Commit b4435cc

Browse files
SeekerWingrix0rrr
authored andcommitted
feat(aws-lambda): add support for XRay Tracing (#675)
1 parent c6c09bf commit b4435cc

File tree

3 files changed

+229
-1
lines changed

3 files changed

+229
-1
lines changed

packages/@aws-cdk/aws-lambda/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,18 @@ const fn = new lambda.Function(this, 'MyFunction', {
7575
```
7676
See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/dlq.html)
7777
to learn more about AWS Lambdas and DLQs.
78+
79+
### Lambda with X-Ray Tracing
80+
81+
```ts
82+
import lambda = require('@aws-cdk/aws-lambda');
83+
84+
const fn = new lambda.Function(this, 'MyFunction', {
85+
runtime: lambda.Runtime.NodeJS810,
86+
handler: 'index.handler'
87+
code: lambda.Code.inline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'),
88+
tracing: lambda.Tracing.Active
89+
});
90+
```
91+
See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html)
92+
to learn more about AWS Lambda's X-Ray support.

packages/@aws-cdk/aws-lambda/lib/lambda.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,26 @@ import { FunctionVersion } from './lambda-version';
88
import { cloudformation, FunctionArn, FunctionName } from './lambda.generated';
99
import { Runtime } from './runtime';
1010

11+
/**
12+
* X-Ray Tracing Modes (https://docs.aws.amazon.com/lambda/latest/dg/API_TracingConfig.html)
13+
*/
14+
export enum Tracing {
15+
/**
16+
* Lambda will respect any tracing header it receives from an upstream service.
17+
* If no tracing header is received, Lambda will call X-Ray for a tracing decision.
18+
*/
19+
Active,
20+
/**
21+
* Lambda will only trace the request from an upstream service
22+
* if it contains a tracing header with "sampled=1"
23+
*/
24+
PassThrough,
25+
/**
26+
* Lambda will not trace any request.
27+
*/
28+
Disabled
29+
}
30+
1131
export interface FunctionProps {
1232
/**
1333
* The source code of your Lambda function. You can point to a file in an
@@ -134,6 +154,13 @@ export interface FunctionProps {
134154
* @default SQS queue with 14 day retention period if `deadLetterQueueEnabled` is `true`
135155
*/
136156
deadLetterQueue?: sqs.QueueRef;
157+
158+
/**
159+
* Enable AWS X-Ray Tracing for Lambda Function.
160+
*
161+
* @default undefined X-Ray tracing disabled
162+
*/
163+
tracing?: Tracing;
137164
}
138165

139166
/**
@@ -216,6 +243,7 @@ export class Function extends FunctionRef {
216243
memorySize: props.memorySize,
217244
vpcConfig: this.configureVpc(props),
218245
deadLetterConfig: this.buildDeadLetterConfig(props),
246+
tracingConfig: this.buildTracingConfig(props)
219247
});
220248

221249
resource.addDependency(this.role);
@@ -332,4 +360,19 @@ export class Function extends FunctionRef {
332360
targetArn: deadLetterQueue.queueArn
333361
};
334362
}
363+
364+
private buildTracingConfig(props: FunctionProps) {
365+
if (props.tracing === undefined || props.tracing === Tracing.Disabled) {
366+
return undefined;
367+
}
368+
369+
this.addToRolePolicy(new cdk.PolicyStatement()
370+
.addActions('xray:PutTraceSegments', 'xray:PutTelemetryRecords')
371+
.addAllResources());
372+
373+
return {
374+
mode: Tracing[props.tracing]
375+
};
376+
}
377+
335378
}

packages/@aws-cdk/aws-lambda/test/test.lambda.ts

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { countResources, expect, haveResource } from '@aws-cdk/assert';
1+
import { countResources, expect, haveResource, ResourcePart } from '@aws-cdk/assert';
22
import events = require('@aws-cdk/aws-events');
33
import iam = require('@aws-cdk/aws-iam');
44
import sqs = require('@aws-cdk/aws-sqs');
@@ -911,6 +911,176 @@ export = {
911911
test.done();
912912
},
913913

914+
'default function with Active tracing'(test: Test) {
915+
const stack = new cdk.Stack();
916+
917+
new lambda.Function(stack, 'MyLambda', {
918+
code: new lambda.InlineCode('foo'),
919+
handler: 'index.handler',
920+
runtime: lambda.Runtime.NodeJS610,
921+
tracing: lambda.Tracing.Active
922+
});
923+
924+
expect(stack).to(haveResource('AWS::IAM::Policy', {
925+
"PolicyDocument": {
926+
"Statement": [
927+
{
928+
"Action": [
929+
"xray:PutTraceSegments",
930+
"xray:PutTelemetryRecords"
931+
],
932+
"Effect": "Allow",
933+
"Resource": "*"
934+
}
935+
],
936+
"Version": "2012-10-17"
937+
},
938+
"PolicyName": "MyLambdaServiceRoleDefaultPolicy5BBC6F68",
939+
"Roles": [
940+
{
941+
"Ref": "MyLambdaServiceRole4539ECB6"
942+
}
943+
]
944+
}));
945+
946+
expect(stack).to(haveResource('AWS::Lambda::Function', {
947+
"Properties": {
948+
"Code": {
949+
"ZipFile": "foo"
950+
},
951+
"Handler": "index.handler",
952+
"Role": {
953+
"Fn::GetAtt": [
954+
"MyLambdaServiceRole4539ECB6",
955+
"Arn"
956+
]
957+
},
958+
"Runtime": "nodejs6.10",
959+
"TracingConfig": {
960+
"Mode": "Active"
961+
}
962+
},
963+
"DependsOn": [
964+
"MyLambdaServiceRole4539ECB6",
965+
"MyLambdaServiceRoleDefaultPolicy5BBC6F68"
966+
]
967+
}, ResourcePart.CompleteDefinition));
968+
969+
test.done();
970+
},
971+
972+
'default function with PassThrough tracing'(test: Test) {
973+
const stack = new cdk.Stack();
974+
975+
new lambda.Function(stack, 'MyLambda', {
976+
code: new lambda.InlineCode('foo'),
977+
handler: 'index.handler',
978+
runtime: lambda.Runtime.NodeJS610,
979+
tracing: lambda.Tracing.PassThrough
980+
});
981+
982+
expect(stack).to(haveResource('AWS::IAM::Policy', {
983+
"PolicyDocument": {
984+
"Statement": [
985+
{
986+
"Action": [
987+
"xray:PutTraceSegments",
988+
"xray:PutTelemetryRecords"
989+
],
990+
"Effect": "Allow",
991+
"Resource": "*"
992+
}
993+
],
994+
"Version": "2012-10-17"
995+
},
996+
"PolicyName": "MyLambdaServiceRoleDefaultPolicy5BBC6F68",
997+
"Roles": [
998+
{
999+
"Ref": "MyLambdaServiceRole4539ECB6"
1000+
}
1001+
]
1002+
}));
1003+
1004+
expect(stack).to(haveResource('AWS::Lambda::Function', {
1005+
"Properties": {
1006+
"Code": {
1007+
"ZipFile": "foo"
1008+
},
1009+
"Handler": "index.handler",
1010+
"Role": {
1011+
"Fn::GetAtt": [
1012+
"MyLambdaServiceRole4539ECB6",
1013+
"Arn"
1014+
]
1015+
},
1016+
"Runtime": "nodejs6.10",
1017+
"TracingConfig": {
1018+
"Mode": "PassThrough"
1019+
}
1020+
},
1021+
"DependsOn": [
1022+
"MyLambdaServiceRole4539ECB6",
1023+
"MyLambdaServiceRoleDefaultPolicy5BBC6F68"
1024+
]
1025+
}, ResourcePart.CompleteDefinition));
1026+
1027+
test.done();
1028+
},
1029+
1030+
'default function with Disabled tracing'(test: Test) {
1031+
const stack = new cdk.Stack();
1032+
1033+
new lambda.Function(stack, 'MyLambda', {
1034+
code: new lambda.InlineCode('foo'),
1035+
handler: 'index.handler',
1036+
runtime: lambda.Runtime.NodeJS610,
1037+
tracing: lambda.Tracing.Disabled
1038+
});
1039+
1040+
expect(stack).notTo(haveResource('AWS::IAM::Policy', {
1041+
"PolicyDocument": {
1042+
"Statement": [
1043+
{
1044+
"Action": [
1045+
"xray:PutTraceSegments",
1046+
"xray:PutTelemetryRecords"
1047+
],
1048+
"Effect": "Allow",
1049+
"Resource": "*"
1050+
}
1051+
],
1052+
"Version": "2012-10-17"
1053+
},
1054+
"PolicyName": "MyLambdaServiceRoleDefaultPolicy5BBC6F68",
1055+
"Roles": [
1056+
{
1057+
"Ref": "MyLambdaServiceRole4539ECB6"
1058+
}
1059+
]
1060+
}));
1061+
1062+
expect(stack).to(haveResource('AWS::Lambda::Function', {
1063+
"Properties": {
1064+
"Code": {
1065+
"ZipFile": "foo"
1066+
},
1067+
"Handler": "index.handler",
1068+
"Role": {
1069+
"Fn::GetAtt": [
1070+
"MyLambdaServiceRole4539ECB6",
1071+
"Arn"
1072+
]
1073+
},
1074+
"Runtime": "nodejs6.10"
1075+
},
1076+
"DependsOn": [
1077+
"MyLambdaServiceRole4539ECB6"
1078+
]
1079+
}, ResourcePart.CompleteDefinition));
1080+
1081+
test.done();
1082+
},
1083+
9141084
};
9151085

9161086
function newTestLambda(parent: cdk.Construct) {

0 commit comments

Comments
 (0)