diff --git a/examples/go-stack/app.go b/examples/go-stack/app.go index 9b606ff9..d9f40658 100644 --- a/examples/go-stack/app.go +++ b/examples/go-stack/app.go @@ -48,8 +48,38 @@ func NewAppStackWithoutDatadog(scope constructs.Construct, id *string, props *Ap return stack, myFunction } -// Creates a stack with Datadog integration set up -func NewAppStackWithDatadog(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { +// Creates a stack with Datadog integration set up, using the new API (DatadogLambda, DatadogLambdaProps) +func NewAppStackWithDatadogLambda(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { + stack, lambdaFunction := NewAppStackWithoutDatadog(scope, &id, props) + + // Set up Datadog integration + datadog := ddcdkconstruct.NewDatadogLambda( + stack, + jsii.String("Datadog"), + &ddcdkconstruct.DatadogLambdaProps{ + NodeLayerVersion: jsii.Number(113), + PythonLayerVersion: jsii.Number(97), + JavaLayerVersion: jsii.Number(21), + DotnetLayerVersion: jsii.Number(15), + AddLayers: jsii.Bool(true), + ExtensionLayerVersion: jsii.Number(62), + FlushMetricsToLogs: jsii.Bool(true), + Site: jsii.String("datadoghq.com"), + ApiKey: jsii.String(os.Getenv("DD_API_KEY")), + EnableDatadogTracing: jsii.Bool(true), + EnableMergeXrayTraces: jsii.Bool(true), + EnableDatadogLogs: jsii.Bool(true), + InjectLogContext: jsii.Bool(true), + LogLevel: jsii.String("debug"), + }) + datadog.AddLambdaFunctions(&[]interface{}{lambdaFunction}, nil) + + return stack +} + +// Creates a stack with Datadog integration set up, using the old API (Datadog, DatadogProps) to ensure +// backward compatibility. Users are recommended to use the new API. +func NewAppStackWithDatadogOldApi(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { stack, lambdaFunction := NewAppStackWithoutDatadog(scope, &id, props) // Set up Datadog integration @@ -82,7 +112,13 @@ func main() { app := awscdk.NewApp(nil) - NewAppStackWithDatadog(app, "AppStack", &AppStackProps{ + NewAppStackWithDatadogLambda(app, "CdkGoStack", &AppStackProps{ + awscdk.StackProps{ + Env: env(), + }, + }) + + NewAppStackWithDatadogOldApi(app, "CdkGoLambdaOldApiStack", &AppStackProps{ awscdk.StackProps{ Env: env(), }, diff --git a/examples/python-stack/app.py b/examples/python-stack/app.py index 417b29f0..1104d47f 100644 --- a/examples/python-stack/app.py +++ b/examples/python-stack/app.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 from aws_cdk import App from cdk_python.cdk_python_stack import CdkPythonStack +from cdk_python.cdk_python_lambda_old_api_stack import CdkPythonLambdaOldApiStack app = App() CdkPythonStack(app, "CdkPythonStack") +CdkPythonLambdaOldApiStack(app, "CdkPythonLambdaOldApiStack") app.synth() diff --git a/examples/python-stack/cdk_python/cdk_python_lambda_old_api_stack.py b/examples/python-stack/cdk_python/cdk_python_lambda_old_api_stack.py new file mode 100644 index 00000000..9193d3e6 --- /dev/null +++ b/examples/python-stack/cdk_python/cdk_python_lambda_old_api_stack.py @@ -0,0 +1,27 @@ +from constructs import Construct +from datadog_cdk_constructs_v2 import Datadog, DatadogProps +import os +from cdk_python.cdk_python_stack_base import CdkPythonStackBase + +class CdkPythonLambdaOldApiStack(CdkPythonStackBase): + def __init__(self, scope: Construct, id: str, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + datadog = Datadog( + self, + "Datadog", + dotnet_layer_version=15, + node_layer_version=107, + python_layer_version=89, + extension_layer_version=55, + add_layers=True, + api_key=os.getenv("DD_API_KEY"), + enable_datadog_tracing=True, + enable_datadog_asm=True, + flush_metrics_to_logs=True, + site="datadoghq.com", + ) + + # Ensure DatadogProps can be imported properly + props = DatadogProps() + datadog.add_lambda_functions(self.lambdaFunctions) diff --git a/examples/python-stack/cdk_python/cdk_python_stack.py b/examples/python-stack/cdk_python/cdk_python_stack.py index fecffca1..a69f9008 100644 --- a/examples/python-stack/cdk_python/cdk_python_stack.py +++ b/examples/python-stack/cdk_python/cdk_python_stack.py @@ -1,5 +1,5 @@ from constructs import Construct -from datadog_cdk_constructs_v2 import Datadog, DatadogProps +from datadog_cdk_constructs_v2 import DatadogLambda, DatadogLambdaProps import os from cdk_python.cdk_python_stack_base import CdkPythonStackBase @@ -7,7 +7,7 @@ class CdkPythonStack(CdkPythonStackBase): def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) - datadog = Datadog( + datadog = DatadogLambda( self, "Datadog", dotnet_layer_version=15, @@ -22,6 +22,6 @@ def __init__(self, scope: Construct, id: str, **kwargs) -> None: site="datadoghq.com", ) - # Ensure DatadogProps can be imported properly - props = DatadogProps() + # Ensure DatadogLambdaProps can be imported properly + props = DatadogLambdaProps() datadog.add_lambda_functions(self.lambdaFunctions) diff --git a/examples/typescript-stack/bin/index.ts b/examples/typescript-stack/bin/index.ts index 0124adb2..3eb20984 100644 --- a/examples/typescript-stack/bin/index.ts +++ b/examples/typescript-stack/bin/index.ts @@ -1,7 +1,9 @@ #!/usr/bin/env node import * as cdk from "aws-cdk-lib"; import { CdkTypeScriptStack } from "../lib/cdk-typescript-stack"; +import { CdkTypeScriptLambdaOldApiStack } from "../lib/cdk-typescript-lambda-old-api-stack"; const app = new cdk.App(); new CdkTypeScriptStack(app, "CdkTypeScriptStack", {}); +new CdkTypeScriptLambdaOldApiStack(app, "CdkTypeScriptLambdaOldApiStack", {}); app.synth(); diff --git a/examples/typescript-stack/lib/cdk-typescript-lambda-old-api-stack.ts b/examples/typescript-stack/lib/cdk-typescript-lambda-old-api-stack.ts new file mode 100644 index 00000000..a6c3c82e --- /dev/null +++ b/examples/typescript-stack/lib/cdk-typescript-lambda-old-api-stack.ts @@ -0,0 +1,29 @@ +import { StackProps } from "aws-cdk-lib"; +import { Construct } from "constructs"; +import { Datadog, DatadogProps } from "datadog-cdk-constructs-v2"; +import { CdkTypeScriptStackBase } from "./cdk-typescript-stack-base"; + +export class CdkTypeScriptLambdaOldApiStack extends CdkTypeScriptStackBase { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + console.log("Instrumenting Lambda Functions in TypeScript stack using the old Datadog Lambda API"); + + const datadogProps: DatadogProps = { + dotnetLayerVersion: 15, + nodeLayerVersion: 108, + pythonLayerVersion: 89, + extensionLayerVersion: 55, + addLayers: true, + apiKey: process.env.DD_API_KEY, + enableDatadogTracing: true, + enableDatadogASM: true, + flushMetricsToLogs: true, + site: "datadoghq.com", + }; + + const datadog = new Datadog(this, "Datadog", datadogProps); + + datadog.addLambdaFunctions(this.lambdaFunctions); + } +} diff --git a/examples/typescript-stack/lib/cdk-typescript-stack-base.ts b/examples/typescript-stack/lib/cdk-typescript-stack-base.ts index 3e6a4407..0ba9e609 100644 --- a/examples/typescript-stack/lib/cdk-typescript-stack-base.ts +++ b/examples/typescript-stack/lib/cdk-typescript-stack-base.ts @@ -6,7 +6,7 @@ import { Function } from "aws-cdk-lib/aws-lambda"; import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations"; import { Construct } from "constructs"; -export class CdkTypeScriptStackBase extends Stack { +export abstract class CdkTypeScriptStackBase extends Stack { protected lambdaFunctions: lambda.Function[]; constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); diff --git a/examples/typescript-stack/lib/cdk-typescript-stack.ts b/examples/typescript-stack/lib/cdk-typescript-stack.ts index 3c220272..9c142b2a 100644 --- a/examples/typescript-stack/lib/cdk-typescript-stack.ts +++ b/examples/typescript-stack/lib/cdk-typescript-stack.ts @@ -1,6 +1,6 @@ import { StackProps } from "aws-cdk-lib"; import { Construct } from "constructs"; -import { Datadog, DatadogProps } from "datadog-cdk-constructs-v2"; +import { DatadogLambda, DatadogLambdaProps } from "datadog-cdk-constructs-v2"; import { CdkTypeScriptStackBase } from "./cdk-typescript-stack-base"; export class CdkTypeScriptStack extends CdkTypeScriptStackBase { @@ -9,7 +9,7 @@ export class CdkTypeScriptStack extends CdkTypeScriptStackBase { console.log("Instrumenting Lambda Functions in TypeScript stack with Datadog"); - const datadogProps: DatadogProps = { + const datadogLambdaProps: DatadogLambdaProps = { dotnetLayerVersion: 15, nodeLayerVersion: 108, pythonLayerVersion: 89, @@ -22,7 +22,7 @@ export class CdkTypeScriptStack extends CdkTypeScriptStackBase { site: "datadoghq.com", }; - const datadog = new Datadog(this, "Datadog", datadogProps); + const datadog = new DatadogLambda(this, "Datadog", datadogLambdaProps); datadog.addLambdaFunctions(this.lambdaFunctions); } diff --git a/integration_tests/snapshots/correct-lambda_go_old_lambda_api_stack-snapshot.json b/integration_tests/snapshots/correct-lambda_go_old_lambda_api_stack-snapshot.json new file mode 100644 index 00000000..216c26cd --- /dev/null +++ b/integration_tests/snapshots/correct-lambda_go_old_lambda_api_stack-snapshot.json @@ -0,0 +1,171 @@ +{ + "Resources": { + "HelloWorldFunctionServiceRole8E0BD458": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "LambdaGoOldLambdaApiStack/HelloWorldFunction/ServiceRole/Resource" + } + }, + "HelloWorldFunctionB2AB6E79": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "\n\t\t exports.handler = async function(event) {\n\t\t\treturn {\n\t\t\t statusCode: 200,\n\t\t\t body: JSON.stringify('Hello World!'),\n\t\t\t};\n\t\t };\n\t\t" + }, + "Environment": { + "Variables": { + "DD_LAMBDA_HANDLER": "index.handler", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "false", + "DD_MERGE_XRAY_TRACES": "true", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_LOG_LEVEL": "debug", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234", + "DD_TAGS": "git.commit.sha:XXXXXXXX,git.repository_url:github.com/DataDog/datadog-cdk-constructs" + } + }, + "Handler": "/opt/nodejs/node_modules/datadog-lambda-js/handler.handler", + "Layers": [ + "arn:aws:lambda:us-east-1:464622532012:layer:Datadog-Node20-x:113", + "arn:aws:lambda:us-east-1:464622532012:layer:Datadog-Extension:62" + ], + "Role": { + "Fn::GetAtt": [ + "HelloWorldFunctionServiceRole8E0BD458", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ] + }, + "DependsOn": [ + "HelloWorldFunctionServiceRole8E0BD458" + ], + "Metadata": { + "aws:cdk:path": "LambdaGoOldLambdaApiStack/HelloWorldFunction/Resource" + } + }, + "HelloWorldFunctionFunctionUrl4150BDAD": { + "Type": "AWS::Lambda::Url", + "Properties": { + "AuthType": "NONE", + "TargetFunctionArn": { + "Fn::GetAtt": [ + "HelloWorldFunctionB2AB6E79", + "Arn" + ] + } + }, + "Metadata": { + "aws:cdk:path": "LambdaGoOldLambdaApiStack/HelloWorldFunction/FunctionUrl/Resource" + } + }, + "HelloWorldFunctioninvokefunctionurlA2CB1A84": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunctionUrl", + "FunctionName": { + "Fn::GetAtt": [ + "HelloWorldFunctionB2AB6E79", + "Arn" + ] + }, + "FunctionUrlAuthType": "NONE", + "Principal": "*" + }, + "Metadata": { + "aws:cdk:path": "LambdaGoOldLambdaApiStack/HelloWorldFunction/invoke-function-url" + } + }, + "CDKMetadata": { + "Type": "AWS::CDK::Metadata", + "Properties": { + "Analytics": "vX:XXXXXX:XXXXXX" + }, + "Metadata": { + "aws:cdk:path": "LambdaGoOldLambdaApiStack/CDKMetadata/Default" + } + } + }, + "Outputs": { + "myFunctionUrlOutput": { + "Value": { + "Fn::GetAtt": [ + "HelloWorldFunctionFunctionUrl4150BDAD", + "FunctionUrl" + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/integration_tests/snapshots/correct-lambda_python_old_lambda_api_stack-snapshot.json b/integration_tests/snapshots/correct-lambda_python_old_lambda_api_stack-snapshot.json new file mode 100644 index 00000000..dc2ba7e1 --- /dev/null +++ b/integration_tests/snapshots/correct-lambda_python_old_lambda_api_stack-snapshot.json @@ -0,0 +1,692 @@ +{ + "Resources": { + "hellonodeServiceRole01BB45E0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/hello-node/ServiceRole/Resource" + } + }, + "hellonode2FDD99B8": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "serverless/dd-cdk-construct-integration-test/dev/XXXXXXXXXXXXX-XXXX-XX-XXXXX:XX:XX.XXXX/dd-cdk-construct-integration-test.zip" + }, + "Environment": { + "Variables": { + "DD_LAMBDA_HANDLER": "hello.lambda_handler", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "true", + "AWS_LAMBDA_EXEC_WRAPPER": "/opt/datadog_wrapper", + "DD_MERGE_XRAY_TRACES": "false", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234", + "DD_TAGS": "git.commit.sha:XXXXXXXX,git.repository_url:github.com/DataDog/datadog-cdk-constructs" + } + }, + "Handler": "/opt/nodejs/node_modules/datadog-lambda-js/handler.handler", + "Layers": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":464622532012:layer:Datadog-Node20-x:107" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":464622532012:layer:Datadog-Extension:55" + ] + ] + } + ], + "MemorySize": 256, + "Role": { + "Fn::GetAtt": [ + "hellonodeServiceRole01BB45E0", + "Arn" + ] + }, + "Runtime": "nodejs20.x", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ], + "Timeout": 10 + }, + "DependsOn": [ + "hellonodeServiceRole01BB45E0" + ], + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/hello-node/Resource", + "aws:asset:path": "asset.XXXXXXXXXXXXX", + "aws:asset:is-bundled": true, + "aws:asset:property": "Code" + } + }, + "hellopythonServiceRoleEBA89F44": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/hello-python/ServiceRole/Resource" + } + }, + "hellopython5270C3B7": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "serverless/dd-cdk-construct-integration-test/dev/XXXXXXXXXXXXX-XXXX-XX-XXXXX:XX:XX.XXXX/dd-cdk-construct-integration-test.zip" + }, + "Environment": { + "Variables": { + "DD_LAMBDA_HANDLER": "hello.lambda_handler", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "true", + "AWS_LAMBDA_EXEC_WRAPPER": "/opt/datadog_wrapper", + "DD_MERGE_XRAY_TRACES": "false", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234", + "DD_TAGS": "git.commit.sha:XXXXXXXX,git.repository_url:github.com/DataDog/datadog-cdk-constructs" + } + }, + "Handler": "datadog_lambda.handler.handler", + "Layers": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":464622532012:layer:Datadog-Python311:89" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":464622532012:layer:Datadog-Extension:55" + ] + ] + } + ], + "MemorySize": 256, + "Role": { + "Fn::GetAtt": [ + "hellopythonServiceRoleEBA89F44", + "Arn" + ] + }, + "Runtime": "python3.11", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ], + "Timeout": 10 + }, + "DependsOn": [ + "hellopythonServiceRoleEBA89F44" + ], + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/hello-python/Resource", + "aws:asset:path": "asset.XXXXXXXXXXXXX", + "aws:asset:is-bundled": true, + "aws:asset:property": "Code" + } + }, + "hellogoServiceRole55E8052E": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/hello-go/ServiceRole/Resource" + } + }, + "hellogoC49842C1": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "serverless/dd-cdk-construct-integration-test/dev/XXXXXXXXXXXXX-XXXX-XX-XXXXX:XX:XX.XXXX/dd-cdk-construct-integration-test.zip" + }, + "Environment": { + "Variables": { + "DD_LAMBDA_HANDLER": "bootstrap", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "true", + "AWS_LAMBDA_EXEC_WRAPPER": "/opt/datadog_wrapper", + "DD_MERGE_XRAY_TRACES": "false", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234", + "DD_TAGS": "git.commit.sha:XXXXXXXX,git.repository_url:github.com/DataDog/datadog-cdk-constructs" + } + }, + "Handler": "bootstrap", + "Layers": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":464622532012:layer:Datadog-Extension:55" + ] + ] + } + ], + "Role": { + "Fn::GetAtt": [ + "hellogoServiceRole55E8052E", + "Arn" + ] + }, + "Runtime": "provided.al2", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ], + "Timeout": 10 + }, + "DependsOn": [ + "hellogoServiceRole55E8052E" + ], + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/hello-go/Resource", + "aws:asset:path": "asset.XXXXXXXXXXXXX", + "aws:asset:is-bundled": true, + "aws:asset:property": "Code" + } + }, + "hellodotnetServiceRoleECADFA84": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + }, + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/hello-dotnet/ServiceRole/Resource" + } + }, + "hellodotnet2DAF2A64": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "serverless/dd-cdk-construct-integration-test/dev/XXXXXXXXXXXXX-XXXX-XX-XXXXX:XX:XX.XXXX/dd-cdk-construct-integration-test.zip" + }, + "Environment": { + "Variables": { + "AWS_LAMBDA_EXEC_WRAPPER": "/opt/datadog_wrapper", + "DD_TRACE_ENABLED": "true", + "DD_SERVERLESS_APPSEC_ENABLED": "true", + "DD_MERGE_XRAY_TRACES": "false", + "DD_LOGS_INJECTION": "false", + "DD_SERVERLESS_LOGS_ENABLED": "true", + "DD_CAPTURE_LAMBDA_PAYLOAD": "false", + "DD_FLUSH_TO_LOG": "false", + "DD_SITE": "datadoghq.com", + "DD_API_KEY": "1234", + "DD_TAGS": "git.commit.sha:XXXXXXXX,git.repository_url:github.com/DataDog/datadog-cdk-constructs" + } + }, + "Handler": "HelloWorld::HelloWorld.Handler::SayHi", + "Layers": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":464622532012:layer:dd-trace-dotnet:15" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:lambda:", + { + "Ref": "AWS::Region" + }, + ":464622532012:layer:Datadog-Extension:55" + ] + ] + } + ], + "MemorySize": 256, + "Role": { + "Fn::GetAtt": [ + "hellodotnetServiceRoleECADFA84", + "Arn" + ] + }, + "Runtime": "dotnet8", + "Tags": [ + { + "Key": "dd_cdk_construct", + "Value": "vX.XX.X" + } + ], + "Timeout": 10 + }, + "DependsOn": [ + "hellodotnetServiceRoleECADFA84" + ], + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/hello-dotnet/Resource", + "aws:asset:path": "asset.XXXXXXXXXXXXX", + "aws:asset:is-bundled": true, + "aws:asset:property": "Code" + } + }, + "CDKMetadata": { + "Type": "AWS::CDK::Metadata", + "Properties": { + "Analytics": "vX:XXXXXX:XXXXXX" + }, + "Metadata": { + "aws:cdk:path": "LambdaPythonOldLambdaApiStack/CDKMetadata/Default" + }, + "Condition": "CDKMetadataAvailable" + } + }, + "Conditions": { + "CDKMetadataAvailable": { + "Fn::Or": [ + { + "Fn::Or": [ + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "af-south-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "ap-east-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "ap-northeast-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "ap-northeast-2" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "ap-south-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "ap-southeast-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "ap-southeast-2" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "ca-central-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-north-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "cn-northwest-1" + ] + } + ] + }, + { + "Fn::Or": [ + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "eu-central-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "eu-north-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "eu-south-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "eu-west-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "eu-west-2" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "eu-west-3" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "il-central-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "me-central-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "me-south-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "sa-east-1" + ] + } + ] + }, + { + "Fn::Or": [ + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "us-east-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "us-east-2" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "us-west-1" + ] + }, + { + "Fn::Equals": [ + { + "Ref": "AWS::Region" + }, + "us-west-2" + ] + } + ] + } + ] + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/integration_tests/stacks/go/helpers.go b/integration_tests/stacks/go/helpers.go new file mode 100644 index 00000000..15dc1c13 --- /dev/null +++ b/integration_tests/stacks/go/helpers.go @@ -0,0 +1,44 @@ +package main + +import ( + "github.com/aws/aws-cdk-go/awscdk/v2" + "github.com/aws/aws-cdk-go/awscdk/v2/awslambda" + "github.com/aws/constructs-go/constructs/v10" + "github.com/aws/jsii-runtime-go" +) + +type AppStackProps struct { + awscdk.StackProps +} + +// Creates a stack without Datadog integration +func NewAppStackWithoutDatadog(scope constructs.Construct, id *string, props *AppStackProps) (awscdk.Stack, awslambda.Function) { + var sprops awscdk.StackProps + if props != nil { + sprops = props.StackProps + } + stack := awscdk.NewStack(scope, id, &sprops) + + myFunction := awslambda.NewFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.FunctionProps{ + Runtime: awslambda.Runtime_NODEJS_20_X(), + Handler: jsii.String("index.handler"), + Code: awslambda.Code_FromInline(jsii.String(` + exports.handler = async function(event) { + return { + statusCode: 200, + body: JSON.stringify('Hello World!'), + }; + }; + `)), + }) + + myFunctionUrl := myFunction.AddFunctionUrl(&awslambda.FunctionUrlOptions{ + AuthType: awslambda.FunctionUrlAuthType_NONE, + }) + + awscdk.NewCfnOutput(stack, jsii.String("myFunctionUrlOutput"), &awscdk.CfnOutputProps{ + Value: myFunctionUrl.Url(), + }) + + return stack, myFunction +} \ No newline at end of file diff --git a/integration_tests/stacks/go/lambda_go_old_lambda_api_stack.go b/integration_tests/stacks/go/lambda_go_old_lambda_api_stack.go new file mode 100644 index 00000000..f2a4dadf --- /dev/null +++ b/integration_tests/stacks/go/lambda_go_old_lambda_api_stack.go @@ -0,0 +1,38 @@ +package main + +import ( + "github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct" + "github.com/aws/aws-cdk-go/awscdk/v2" + "github.com/aws/constructs-go/constructs/v10" + "github.com/aws/jsii-runtime-go" +) + +// Creates a stack with Datadog integration set up, using the old API (Datadog, DatadogProps) to ensure +// backward compatibility. Users are recommended to use the new API (DatadogLambda, DatadogLambdaProps). +func NewAppStackWithDatadogOldApi(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { + stack, lambdaFunction := NewAppStackWithoutDatadog(scope, &id, props) + + // Set up Datadog integration + datadog := ddcdkconstruct.NewDatadog( + stack, + jsii.String("Datadog"), + &ddcdkconstruct.DatadogProps{ + NodeLayerVersion: jsii.Number(113), + PythonLayerVersion: jsii.Number(97), + JavaLayerVersion: jsii.Number(21), + DotnetLayerVersion: jsii.Number(15), + AddLayers: jsii.Bool(true), + ExtensionLayerVersion: jsii.Number(62), + FlushMetricsToLogs: jsii.Bool(true), + Site: jsii.String("datadoghq.com"), + ApiKey: jsii.String("1234"), + EnableDatadogTracing: jsii.Bool(true), + EnableMergeXrayTraces: jsii.Bool(true), + EnableDatadogLogs: jsii.Bool(true), + InjectLogContext: jsii.Bool(true), + LogLevel: jsii.String("debug"), + }) + + datadog.AddLambdaFunctions(&[]interface{}{lambdaFunction}, nil) + return stack +} diff --git a/integration_tests/stacks/go/lambda_go_stack.go b/integration_tests/stacks/go/lambda_go_stack.go index c1c899a7..0a49864b 100644 --- a/integration_tests/stacks/go/lambda_go_stack.go +++ b/integration_tests/stacks/go/lambda_go_stack.go @@ -3,58 +3,19 @@ package main import ( "github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct" "github.com/aws/aws-cdk-go/awscdk/v2" - "github.com/aws/aws-cdk-go/awscdk/v2/awslambda" "github.com/aws/constructs-go/constructs/v10" "github.com/aws/jsii-runtime-go" ) -type AppStackProps struct { - awscdk.StackProps -} - -// Creates a stack without Datadog integration -func NewAppStackWithoutDatadog(scope constructs.Construct, id *string, props *AppStackProps) (awscdk.Stack, awslambda.Function) { - var sprops awscdk.StackProps - if props != nil { - sprops = props.StackProps - } - stack := awscdk.NewStack(scope, id, &sprops) - - myFunction := awslambda.NewFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.FunctionProps{ - Runtime: awslambda.Runtime_NODEJS_20_X(), // Provide any supported Node.js runtime - Handler: jsii.String("index.handler"), - Code: awslambda.Code_FromInline(jsii.String(` - exports.handler = async function(event) { - return { - statusCode: 200, - body: JSON.stringify('Hello World!'), - }; - }; - `)), - }) - - // Define the Lambda function URL resource - myFunctionUrl := myFunction.AddFunctionUrl(&awslambda.FunctionUrlOptions{ - AuthType: awslambda.FunctionUrlAuthType_NONE, - }) - - // Define a CloudFormation output for your URL - awscdk.NewCfnOutput(stack, jsii.String("myFunctionUrlOutput"), &awscdk.CfnOutputProps{ - Value: myFunctionUrl.Url(), - }) - - return stack, myFunction -} - -// Creates a stack with Datadog integration set up -func NewAppStackWithDatadog(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { +// Creates a stack with Datadog integration using the new API (DatadogLambda, DatadogLambdaProps) +func NewAppStackWithDatadogLambda(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { stack, lambdaFunction := NewAppStackWithoutDatadog(scope, &id, props) // Set up Datadog integration - datadog := ddcdkconstruct.NewDatadog( + datadog := ddcdkconstruct.NewDatadogLambda( stack, jsii.String("Datadog"), - &ddcdkconstruct.DatadogProps{ + &ddcdkconstruct.DatadogLambdaProps{ NodeLayerVersion: jsii.Number(113), PythonLayerVersion: jsii.Number(97), JavaLayerVersion: jsii.Number(21), @@ -70,31 +31,8 @@ func NewAppStackWithDatadog(scope constructs.Construct, id string, props *AppSta InjectLogContext: jsii.Bool(true), LogLevel: jsii.String("debug"), }) - datadog.AddLambdaFunctions(&[]interface{}{lambdaFunction}, nil) + datadog.AddLambdaFunctions(&[]interface{}{lambdaFunction}, nil) return stack } -func main() { - defer jsii.Close() - - app := awscdk.NewApp(nil) - - NewAppStackWithDatadog(app, "LambdaGoStack", &AppStackProps{ - awscdk.StackProps{ - Env: env(), - }, - }) - - app.Synth(nil) -} - -// env determines the AWS environment (account+region) in which our stack is to -// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html -func env() *awscdk.Environment { - env := awscdk.Environment{ - Account: jsii.String("425362996713"), - Region: jsii.String("us-east-1"), - } - return &env -} diff --git a/integration_tests/stacks/go/main.go b/integration_tests/stacks/go/main.go new file mode 100644 index 00000000..851a3a53 --- /dev/null +++ b/integration_tests/stacks/go/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "github.com/aws/aws-cdk-go/awscdk/v2" + "github.com/aws/jsii-runtime-go" +) + +func main() { + defer jsii.Close() + + app := awscdk.NewApp(nil) + + // Creates a stack using the new API (DatadogLambda, DatadogLambdaProps) + NewAppStackWithDatadogLambda(app, "LambdaGoStack", &AppStackProps{ + StackProps: awscdk.StackProps{ + Env: env(), + }, + }) + + // Creates a stack using the old API (Datadog, DatadogProps) + NewAppStackWithDatadogOldApi(app, "LambdaGoOldLambdaApiStack", &AppStackProps{ + StackProps: awscdk.StackProps{ + Env: env(), + }, + }) + + app.Synth(nil) +} + +// env determines the AWS environment (account + region) +func env() *awscdk.Environment { + return &awscdk.Environment{ + Account: jsii.String("425362996713"), + Region: jsii.String("us-east-1"), + } +} diff --git a/integration_tests/stacks/python/.gitignore b/integration_tests/stacks/python/.gitignore new file mode 100644 index 00000000..dc82016f --- /dev/null +++ b/integration_tests/stacks/python/.gitignore @@ -0,0 +1 @@ +datadog-cdk-constructs-*.tar.gz \ No newline at end of file diff --git a/integration_tests/stacks/python/lambda_python_old_lambda_api_stack.py b/integration_tests/stacks/python/lambda_python_old_lambda_api_stack.py new file mode 100644 index 00000000..7ffa2814 --- /dev/null +++ b/integration_tests/stacks/python/lambda_python_old_lambda_api_stack.py @@ -0,0 +1,32 @@ +from constructs import Construct +from datadog_cdk_constructs_v2 import Datadog, DatadogProps +from aws_cdk import App + +from lambda_python_stack_base import LambdaPythonStackBase + +class LambdaPythonOldLambdaApiStack(LambdaPythonStackBase): + def __init__(self, scope: Construct, id: str, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + datadog = Datadog( + self, + "Datadog", + dotnet_layer_version=15, + node_layer_version=107, + python_layer_version=89, + extension_layer_version=55, + add_layers=True, + api_key="1234", + enable_datadog_tracing=True, + enable_datadog_asm=True, + flush_metrics_to_logs=True, + site="datadoghq.com", + ) + + # Ensure DatadogProps can be imported properly + props = DatadogProps() + datadog.add_lambda_functions(self.lambdaFunctions) + +app = App() +LambdaPythonOldLambdaApiStack(app, "LambdaPythonOldLambdaApiStack") +app.synth() \ No newline at end of file diff --git a/integration_tests/stacks/python/lambda_python_stack.py b/integration_tests/stacks/python/lambda_python_stack.py index 825138d3..addf109d 100644 --- a/integration_tests/stacks/python/lambda_python_stack.py +++ b/integration_tests/stacks/python/lambda_python_stack.py @@ -1,5 +1,5 @@ from constructs import Construct -from datadog_cdk_constructs_v2 import Datadog, DatadogProps +from datadog_cdk_constructs_v2 import DatadogLambda, DatadogLambdaProps from aws_cdk import App from lambda_python_stack_base import LambdaPythonStackBase @@ -8,7 +8,7 @@ class LambdaPythonStack(LambdaPythonStackBase): def __init__(self, scope: Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) - datadog = Datadog( + datadog = DatadogLambda( self, "Datadog", dotnet_layer_version=15, @@ -23,8 +23,8 @@ def __init__(self, scope: Construct, id: str, **kwargs) -> None: site="datadoghq.com", ) - # Ensure DatadogProps can be imported properly - props = DatadogProps() + # Ensure DatadogLambdaProps can be imported properly + props = DatadogLambdaProps() datadog.add_lambda_functions(self.lambdaFunctions) app = App() diff --git a/scripts/run_integration_tests.sh b/scripts/run_integration_tests.sh index b832cf2f..85461e44 100755 --- a/scripts/run_integration_tests.sh +++ b/scripts/run_integration_tests.sh @@ -22,7 +22,9 @@ STACK_CONFIG_PATHS=( "typescript/lambda-python-function-stack.ts" "typescript/lambda-java-function-stack.ts" "python/lambda_python_stack.py" + "python/lambda_python_old_lambda_api_stack.py" "go/lambda_go_stack.go" + "go/lambda_go_old_lambda_api_stack.go" ) SCRIPT_PATH=${BASH_SOURCE[0]} @@ -132,12 +134,13 @@ for ((i = 0; i < ${#STACK_CONFIG_PATHS[@]}; i++)); do # Strip the "go/" prefix STACK_CONFIG_NAME="${STACK_CONFIG_PATH_NO_EXT#go/}" + # convert snake_case to PascalCase (e.g. lambda_go_stack to LambdaGoStack) to match the + # name of the Go stack + STACK_CONFIG_NAME_PASCAL_CASE=$(snake_case_to_pascal_case "$STACK_CONFIG_NAME") + cd stacks/go - cdk synth --app "go run $STACK_CONFIG_NAME.go" --json --quiet + cdk synth $STACK_CONFIG_NAME_PASCAL_CASE --app "go run *.go" --json --quiet cd ../.. - # convert snake_case to PascalCase (e.g. lambda_python_stack to LambdaPythonStack) to match the - # name of the generated json file for the Go stack - STACK_CONFIG_NAME_PASCAL_CASE=$(snake_case_to_pascal_case "$STACK_CONFIG_NAME") RAW_CFN_TEMPLATE="stacks/go/cdk.out/$STACK_CONFIG_NAME_PASCAL_CASE.template.json" else echo "Invalid stack config path: ${STACK_CONFIG_PATHS[i]}" diff --git a/src/constants.ts b/src/constants.ts index 74506369..49752aa9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -27,7 +27,7 @@ export enum RuntimeType { UNSUPPORTED, } -export const DefaultDatadogProps = { +export const DatadogLambdaDefaultProps = { addLayers: true, enableDatadogTracing: true, enableDatadogASM: false, @@ -40,6 +40,12 @@ export const DefaultDatadogProps = { grantSecretReadAccess: true, }; +/** + * For backward compatibility. It's recommended to use DatadogLambdaDefaultProps for + * users who want to add Datadog monitoring for Lambda functions. + */ +export const DatadogDefaultProps = DatadogLambdaDefaultProps; + export enum TagKeys { CDK = "dd_cdk_construct", ENV = "env", diff --git a/src/datadog-lambda.ts b/src/datadog-lambda.ts index 0a8fd941..9c32ea97 100644 --- a/src/datadog-lambda.ts +++ b/src/datadog-lambda.ts @@ -19,11 +19,11 @@ import { addForwarderToLogGroups, applyEnvVariables, TagKeys, - DatadogStrictProps, + DatadogLambdaStrictProps, setGitEnvironmentVariables, setDDEnvVariables, - DefaultDatadogProps, - DatadogProps, + DatadogLambdaDefaultProps, + DatadogLambdaProps, Transport, } from "./index"; import { LambdaFunction } from "./interfaces"; @@ -32,9 +32,10 @@ const versionJson = require("../version.json"); export class DatadogLambda extends Construct { scope: Construct; - props: DatadogProps; + props: DatadogLambdaProps; transport: Transport; - constructor(scope: Construct, id: string, props: DatadogProps) { + + constructor(scope: Construct, id: string, props: DatadogLambdaProps) { if (process.env.DD_CONSTRUCT_DEBUG_LOGS?.toLowerCase() == "true") { log.setLevel("debug"); } @@ -59,7 +60,7 @@ export class DatadogLambda extends Construct { public addLambdaFunctions(lambdaFunctions: LambdaFunction[], construct?: Construct): void { // baseProps contains all properties set by the user, with default values for properties // defined in DefaultDatadogProps (if not set by user) - const baseProps: DatadogStrictProps = handleSettingPropDefaults(this.props); + const baseProps: DatadogLambdaStrictProps = handleSettingPropDefaults(this.props); const extractedLambdaFunctions = extractSingletonFunctions(lambdaFunctions); @@ -160,7 +161,7 @@ export function addCdkConstructVersionTag(lambdaFunctions: lambda.Function[]): v }); } -function setTags(lambdaFunctions: lambda.Function[], props: DatadogProps): void { +function setTags(lambdaFunctions: lambda.Function[], props: DatadogLambdaProps): void { log.debug(`Adding datadog tags`); lambdaFunctions.forEach((functionName) => { if (props.forwarderArn) { @@ -214,7 +215,7 @@ function isSingletonFunction(fn: LambdaFunction): fn is lambda.SingletonFunction return fn.hasOwnProperty("lambdaFunction"); } -export function validateProps(props: DatadogProps, apiKeyArnOverride = false): void { +export function validateProps(props: DatadogLambdaProps, apiKeyArnOverride = false): void { log.debug("Validating props..."); checkForMultipleApiKeys(props, apiKeyArnOverride); @@ -268,7 +269,7 @@ export function validateProps(props: DatadogProps, apiKeyArnOverride = false): v } } -export function checkForMultipleApiKeys(props: DatadogProps, apiKeyArnOverride = false): void { +export function checkForMultipleApiKeys(props: DatadogLambdaProps, apiKeyArnOverride = false): void { let multipleApiKeysMessage; const apiKeyArnOrOverride = props.apiKeySecretArn !== undefined || apiKeyArnOverride; if (props.apiKey !== undefined && props.apiKmsKey !== undefined && apiKeyArnOrOverride) { @@ -286,7 +287,7 @@ export function checkForMultipleApiKeys(props: DatadogProps, apiKeyArnOverride = } } -export function handleSettingPropDefaults(props: DatadogProps): DatadogStrictProps { +export function handleSettingPropDefaults(props: DatadogLambdaProps): DatadogLambdaStrictProps { let addLayers = props.addLayers; let enableDatadogTracing = props.enableDatadogTracing; let enableDatadogASM = props.enableDatadogASM; @@ -301,51 +302,59 @@ export function handleSettingPropDefaults(props: DatadogProps): DatadogStrictPro const extensionLayerVersion = props.extensionLayerVersion; if (addLayers === undefined) { - log.debug(`No value provided for addLayers, defaulting to ${DefaultDatadogProps.addLayers}`); - addLayers = DefaultDatadogProps.addLayers; + log.debug(`No value provided for addLayers, defaulting to ${DatadogLambdaDefaultProps.addLayers}`); + addLayers = DatadogLambdaDefaultProps.addLayers; } if (enableDatadogTracing === undefined) { - log.debug(`No value provided for enableDatadogTracing, defaulting to ${DefaultDatadogProps.enableDatadogTracing}`); - enableDatadogTracing = DefaultDatadogProps.enableDatadogTracing; + log.debug( + `No value provided for enableDatadogTracing, defaulting to ${DatadogLambdaDefaultProps.enableDatadogTracing}`, + ); + enableDatadogTracing = DatadogLambdaDefaultProps.enableDatadogTracing; } if (enableDatadogASM === undefined) { - log.debug(`No value provided for enableDatadogASM, defaulting to ${DefaultDatadogProps.enableDatadogASM}`); - enableDatadogASM = DefaultDatadogProps.enableDatadogASM; + log.debug(`No value provided for enableDatadogASM, defaulting to ${DatadogLambdaDefaultProps.enableDatadogASM}`); + enableDatadogASM = DatadogLambdaDefaultProps.enableDatadogASM; } if (enableMergeXrayTraces === undefined) { log.debug( - `No value provided for enableMergeXrayTraces, defaulting to ${DefaultDatadogProps.enableMergeXrayTraces}`, + `No value provided for enableMergeXrayTraces, defaulting to ${DatadogLambdaDefaultProps.enableMergeXrayTraces}`, ); - enableMergeXrayTraces = DefaultDatadogProps.enableMergeXrayTraces; + enableMergeXrayTraces = DatadogLambdaDefaultProps.enableMergeXrayTraces; } if (injectLogContext === undefined) { - log.debug(`No value provided for injectLogContext, defaulting to ${DefaultDatadogProps.injectLogContext}`); - injectLogContext = DefaultDatadogProps.injectLogContext; + log.debug(`No value provided for injectLogContext, defaulting to ${DatadogLambdaDefaultProps.injectLogContext}`); + injectLogContext = DatadogLambdaDefaultProps.injectLogContext; } if (logLevel === undefined) { log.debug(`No value provided for logLevel`); } if (enableDatadogLogs === undefined) { - log.debug(`No value provided for enableDatadogLogs, defaulting to ${DefaultDatadogProps.enableDatadogLogs}`); - enableDatadogLogs = DefaultDatadogProps.enableDatadogLogs; + log.debug(`No value provided for enableDatadogLogs, defaulting to ${DatadogLambdaDefaultProps.enableDatadogLogs}`); + enableDatadogLogs = DatadogLambdaDefaultProps.enableDatadogLogs; } if (captureLambdaPayload === undefined) { - log.debug(`No value provided for captureLambdaPayload, default to ${DefaultDatadogProps.captureLambdaPayload}`); - captureLambdaPayload = DefaultDatadogProps.captureLambdaPayload; + log.debug( + `No value provided for captureLambdaPayload, default to ${DatadogLambdaDefaultProps.captureLambdaPayload}`, + ); + captureLambdaPayload = DatadogLambdaDefaultProps.captureLambdaPayload; } if (sourceCodeIntegration === undefined) { - log.debug(`No value provided for sourceCodeIntegration, default to ${DefaultDatadogProps.sourceCodeIntegration}`); - sourceCodeIntegration = DefaultDatadogProps.sourceCodeIntegration; + log.debug( + `No value provided for sourceCodeIntegration, default to ${DatadogLambdaDefaultProps.sourceCodeIntegration}`, + ); + sourceCodeIntegration = DatadogLambdaDefaultProps.sourceCodeIntegration; } if (redirectHandler === undefined) { - log.debug(`No value provided for redirectHandler, default to ${DefaultDatadogProps.redirectHandler}`); - redirectHandler = DefaultDatadogProps.redirectHandler; + log.debug(`No value provided for redirectHandler, default to ${DatadogLambdaDefaultProps.redirectHandler}`); + redirectHandler = DatadogLambdaDefaultProps.redirectHandler; } if (grantSecretReadAccess === undefined) { - log.debug(`No value provided for grantSecretReadAccess, default to ${DefaultDatadogProps.grantSecretReadAccess}`); - grantSecretReadAccess = DefaultDatadogProps.grantSecretReadAccess; + log.debug( + `No value provided for grantSecretReadAccess, default to ${DatadogLambdaDefaultProps.grantSecretReadAccess}`, + ); + grantSecretReadAccess = DatadogLambdaDefaultProps.grantSecretReadAccess; } return { diff --git a/src/datadog.ts b/src/datadog.ts index 72495ddf..688eee40 100644 --- a/src/datadog.ts +++ b/src/datadog.ts @@ -1,3 +1,16 @@ +import { Construct } from "constructs"; import { DatadogLambda } from "./datadog-lambda"; +import { DatadogProps } from "./index"; -export class Datadog extends DatadogLambda {} +/** + * For backward compatibility. It's recommended to use DatadogLambda for + * users who want to add Datadog monitoring for Lambda functions. + */ +export class Datadog extends DatadogLambda { + // Explicitly make the constructor accept DatadogProps, otherwise in the + // Go package, NewDatadog() will only take DatadogLambdaProps and won't take + // DatadogProps. + constructor(scope: Construct, id: string, props: DatadogProps) { + super(scope, id, props); + } +} diff --git a/src/env.ts b/src/env.ts index f36b7157..a8fe68e9 100644 --- a/src/env.ts +++ b/src/env.ts @@ -8,7 +8,7 @@ import * as lambda from "aws-cdk-lib/aws-lambda"; import log from "loglevel"; -import { DatadogProps, DatadogStrictProps } from "./interfaces"; +import { DatadogLambdaProps, DatadogLambdaStrictProps } from "./interfaces"; export const AWS_LAMBDA_EXEC_WRAPPER_KEY = "AWS_LAMBDA_EXEC_WRAPPER"; export const AWS_LAMBDA_EXEC_WRAPPER_VAL = "/opt/datadog_wrapper"; @@ -98,7 +98,7 @@ function filterSensitiveInfoFromRepository(repositoryUrl: string): string { } } -export function applyEnvVariables(lambdas: lambda.Function[], baseProps: DatadogStrictProps): void { +export function applyEnvVariables(lambdas: lambda.Function[], baseProps: DatadogLambdaStrictProps): void { log.debug(`Setting environment variables...`); lambdas.forEach((lam) => { lam.addEnvironment(ENABLE_DD_TRACING_ENV_VAR, baseProps.enableDatadogTracing.toString().toLowerCase()); @@ -122,7 +122,7 @@ export function applyEnvVariables(lambdas: lambda.Function[], baseProps: Datadog }); } -export function setDDEnvVariables(lambdas: lambda.Function[], props: DatadogProps): void { +export function setDDEnvVariables(lambdas: lambda.Function[], props: DatadogLambdaProps): void { lambdas.forEach((lam) => { if (props.extensionLayerVersion) { if (props.env) { diff --git a/src/interfaces.ts b/src/interfaces.ts index 1dbb5922..3287e352 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -9,7 +9,7 @@ import * as lambda from "aws-cdk-lib/aws-lambda"; import * as secrets from "aws-cdk-lib/aws-secretsmanager"; -export interface DatadogProps { +export interface DatadogLambdaProps { readonly dotnetLayerVersion?: number; readonly pythonLayerVersion?: number; readonly nodeLayerVersion?: number; @@ -48,10 +48,16 @@ export interface DatadogProps { readonly useLayersFromAccount?: string; } +/** + * For backward compatibility. It's recommended to use DatadogLambdaProps for + * users who want to add Datadog monitoring for Lambda functions. + */ +export interface DatadogProps extends DatadogLambdaProps {} + /* - * Makes fields shared with DefaultDatadogProps (in constants file) required. + * Makes fields shared with DefaultDatadogLambdaProps (in constants file) required. */ -export interface DatadogStrictProps { +export interface DatadogLambdaStrictProps { readonly addLayers: boolean; readonly enableDatadogLogs: boolean; readonly captureLambdaPayload: boolean; @@ -76,6 +82,12 @@ export interface DatadogStrictProps { readonly redirectHandler?: boolean; } +/** + * For backward compatibility. It's recommended to use DatadogLambdaStrictProps for + * users who want to add Datadog monitoring for Lambda functions. + */ +export interface DatadogStrictProps extends DatadogLambdaStrictProps {} + export interface Runtime { readonly name: string; }