Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for XRay Tracing configuration in Lambda CDK Construct #675

Merged
merged 2 commits into from
Sep 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/@aws-cdk/aws-lambda/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,18 @@ const fn = new lambda.Function(this, 'MyFunction', {
```
See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/dlq.html)
to learn more about AWS Lambdas and DLQs.

### Lambda with X-Ray Tracing

```ts
import lambda = require('@aws-cdk/aws-lambda');

const fn = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NodeJS810,
handler: 'index.handler'
code: lambda.Code.inline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'),
tracing: lambda.Tracing.Active
});
```
See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html)
to learn more about AWS Lambda's X-Ray support.
43 changes: 43 additions & 0 deletions packages/@aws-cdk/aws-lambda/lib/lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ import { FunctionVersion } from './lambda-version';
import { cloudformation, FunctionArn, FunctionName } from './lambda.generated';
import { Runtime } from './runtime';

/**
* X-Ray Tracing Modes (https://docs.aws.amazon.com/lambda/latest/dg/API_TracingConfig.html)
*/
export enum Tracing {
/**
* Lambda will respect any tracing header it receives from an upstream service.
* If no tracing header is received, Lambda will call X-Ray for a tracing decision.
*/
Active,
/**
* Lambda will only trace the request from an upstream service
* if it contains a tracing header with "sampled=1"
*/
PassThrough,
/**
* Lambda will not trace any request.
*/
Disabled
}

export interface FunctionProps {
/**
* The source code of your Lambda function. You can point to a file in an
Expand Down Expand Up @@ -134,6 +154,13 @@ export interface FunctionProps {
* @default SQS queue with 14 day retention period if `deadLetterQueueEnabled` is `true`
*/
deadLetterQueue?: sqs.QueueRef;

/**
* Enable AWS X-Ray Tracing for Lambda Function.
*
* @default undefined X-Ray tracing disabled
*/
tracing?: Tracing;
}

/**
Expand Down Expand Up @@ -216,6 +243,7 @@ export class Function extends FunctionRef {
memorySize: props.memorySize,
vpcConfig: this.configureVpc(props),
deadLetterConfig: this.buildDeadLetterConfig(props),
tracingConfig: this.buildTracingConfig(props)
});

resource.addDependency(this.role);
Expand Down Expand Up @@ -332,4 +360,19 @@ export class Function extends FunctionRef {
targetArn: deadLetterQueue.queueArn
};
}

private buildTracingConfig(props: FunctionProps) {
if (props.tracing === undefined || props.tracing === Tracing.Disabled) {
return undefined;
}

this.addToRolePolicy(new cdk.PolicyStatement()
.addActions('xray:PutTraceSegments', 'xray:PutTelemetryRecords')
.addAllResources());

return {
mode: Tracing[props.tracing]
};
}

}
172 changes: 171 additions & 1 deletion packages/@aws-cdk/aws-lambda/test/test.lambda.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { countResources, expect, haveResource } from '@aws-cdk/assert';
import { countResources, expect, haveResource, ResourcePart } from '@aws-cdk/assert';
import events = require('@aws-cdk/aws-events');
import iam = require('@aws-cdk/aws-iam');
import sqs = require('@aws-cdk/aws-sqs');
Expand Down Expand Up @@ -911,6 +911,176 @@ export = {
test.done();
},

'default function with Active tracing'(test: Test) {
const stack = new cdk.Stack();

new lambda.Function(stack, 'MyLambda', {
code: new lambda.InlineCode('foo'),
handler: 'index.handler',
runtime: lambda.Runtime.NodeJS610,
tracing: lambda.Tracing.Active
});

expect(stack).to(haveResource('AWS::IAM::Policy', {
"PolicyDocument": {
"Statement": [
{
"Action": [
"xray:PutTraceSegments",
"xray:PutTelemetryRecords"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": "MyLambdaServiceRoleDefaultPolicy5BBC6F68",
"Roles": [
{
"Ref": "MyLambdaServiceRole4539ECB6"
}
]
}));

expect(stack).to(haveResource('AWS::Lambda::Function', {
"Properties": {
"Code": {
"ZipFile": "foo"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"MyLambdaServiceRole4539ECB6",
"Arn"
]
},
"Runtime": "nodejs6.10",
"TracingConfig": {
"Mode": "Active"
}
},
"DependsOn": [
"MyLambdaServiceRole4539ECB6",
"MyLambdaServiceRoleDefaultPolicy5BBC6F68"
]
}, ResourcePart.CompleteDefinition));

test.done();
},

'default function with PassThrough tracing'(test: Test) {
const stack = new cdk.Stack();

new lambda.Function(stack, 'MyLambda', {
code: new lambda.InlineCode('foo'),
handler: 'index.handler',
runtime: lambda.Runtime.NodeJS610,
tracing: lambda.Tracing.PassThrough
});

expect(stack).to(haveResource('AWS::IAM::Policy', {
"PolicyDocument": {
"Statement": [
{
"Action": [
"xray:PutTraceSegments",
"xray:PutTelemetryRecords"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": "MyLambdaServiceRoleDefaultPolicy5BBC6F68",
"Roles": [
{
"Ref": "MyLambdaServiceRole4539ECB6"
}
]
}));

expect(stack).to(haveResource('AWS::Lambda::Function', {
"Properties": {
"Code": {
"ZipFile": "foo"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"MyLambdaServiceRole4539ECB6",
"Arn"
]
},
"Runtime": "nodejs6.10",
"TracingConfig": {
"Mode": "PassThrough"
}
},
"DependsOn": [
"MyLambdaServiceRole4539ECB6",
"MyLambdaServiceRoleDefaultPolicy5BBC6F68"
]
}, ResourcePart.CompleteDefinition));

test.done();
},

'default function with Disabled tracing'(test: Test) {
const stack = new cdk.Stack();

new lambda.Function(stack, 'MyLambda', {
code: new lambda.InlineCode('foo'),
handler: 'index.handler',
runtime: lambda.Runtime.NodeJS610,
tracing: lambda.Tracing.Disabled
});

expect(stack).notTo(haveResource('AWS::IAM::Policy', {
"PolicyDocument": {
"Statement": [
{
"Action": [
"xray:PutTraceSegments",
"xray:PutTelemetryRecords"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": "MyLambdaServiceRoleDefaultPolicy5BBC6F68",
"Roles": [
{
"Ref": "MyLambdaServiceRole4539ECB6"
}
]
}));

expect(stack).to(haveResource('AWS::Lambda::Function', {
"Properties": {
"Code": {
"ZipFile": "foo"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"MyLambdaServiceRole4539ECB6",
"Arn"
]
},
"Runtime": "nodejs6.10"
},
"DependsOn": [
"MyLambdaServiceRole4539ECB6"
]
}, ResourcePart.CompleteDefinition));

test.done();
},

};

function newTestLambda(parent: cdk.Construct) {
Expand Down