├── .eslintrc.json ├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report_template.md │ └── feature_request_template.md ├── pull_request_template.md └── workflows │ ├── build.yml │ ├── codeql-analysis.yml │ ├── integration_tests.yml │ ├── pull-request-lint.yml │ └── upgrade.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── .projen ├── deps.json ├── files.json └── tasks.json ├── .projenrc.js ├── .versionrc.json ├── .yarn └── releases │ └── yarn-1.22.19.cjs ├── .yarnrc.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE-3rdparty.csv ├── NOTICE ├── README.md ├── examples ├── ecs │ ├── go-stack │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app.go │ │ ├── cdk.json │ │ ├── go.mod │ │ └── go.sum │ ├── python-stack │ │ ├── README.md │ │ ├── app.py │ │ ├── cdk.json │ │ ├── cdk_python │ │ │ ├── __init__.py │ │ │ └── cdk_python_stack.py │ │ └── requirements.txt │ └── typescript-stack │ │ ├── .npmignore │ │ ├── README.md │ │ ├── cdk.json │ │ ├── lib │ │ └── cdk-typescript-stack.ts │ │ ├── package.json │ │ └── yarn.lock ├── go-stack │ ├── .gitignore │ ├── README.md │ ├── app.go │ ├── cdk.json │ ├── go.mod │ └── go.sum ├── lambda │ ├── dotnet │ │ ├── Handler.cs │ │ └── HelloWorld.csproj │ ├── go │ │ ├── go.mod │ │ ├── go.sum │ │ └── hello.go │ ├── node │ │ ├── hello.js │ │ ├── package-lock.json │ │ └── package.json │ └── python │ │ ├── hello.py │ │ └── requirements.txt ├── python-stack │ ├── README.md │ ├── app.py │ ├── cdk.json │ ├── cdk_python │ │ ├── __init__.py │ │ ├── cdk_python_stack.py │ │ └── cdk_python_stack_base.py │ └── requirements.txt ├── step-functions-go-stack │ ├── .gitignore │ ├── README.md │ ├── app.go │ ├── cdk.json │ ├── go.mod │ └── go.sum ├── step-functions-python-stack │ ├── README.md │ ├── app.py │ ├── cdk.json │ ├── cdk_step_functions_python_stack.py │ ├── datadog-cdk-constructs-v2-1.18.0.tar.gz │ └── requirements.txt ├── step-functions-typescript-stack │ ├── .npmignore │ ├── README.md │ ├── bin │ │ └── index.ts │ ├── cdk.json │ ├── lib │ │ └── cdk-step-functions-typescript-stack.ts │ ├── package.json │ └── yarn.lock └── typescript-stack │ ├── .npmignore │ ├── README.md │ ├── bin │ └── index.ts │ ├── cdk.json │ ├── lib │ ├── cdk-typescript-stack-base.ts │ └── cdk-typescript-stack.ts │ ├── package.json │ ├── tsconfig.json │ └── yarn.lock ├── integration_tests ├── lambda │ ├── example-java.java │ ├── example-lambda.ts │ └── example-python.py ├── snapshots │ ├── .gitignore │ ├── correct-apigateway-stack-snapshot.json │ ├── correct-ecs-fargate-stack-snapshot.json │ ├── correct-lambda-function-arm-stack-snapshot.json │ ├── correct-lambda-function-stack-snapshot.json │ ├── correct-lambda-java-function-stack-snapshot.json │ ├── correct-lambda-nodejs-function-stack-snapshot.json │ ├── correct-lambda-provided-arm-stack-snapshot.json │ ├── correct-lambda-provided-stack-snapshot.json │ ├── correct-lambda-python-function-stack-snapshot.json │ ├── correct-lambda-singleton-function-stack-snapshot.json │ ├── correct-lambda_go_stack-snapshot.json │ ├── correct-lambda_python_stack-snapshot.json │ ├── correct-step-function-stack-snapshot.json │ ├── correct-step_functions_go_stack-snapshot.json │ └── correct-step_functions_python_stack-snapshot.json ├── stacks │ ├── go │ │ ├── .gitignore │ │ ├── go.mod │ │ ├── go.sum │ │ ├── helpers.go │ │ ├── lambda_go_stack.go │ │ ├── main.go │ │ └── step_functions_go_stack.go │ ├── python │ │ ├── .gitignore │ │ ├── lambda_python_stack.py │ │ ├── lambda_python_stack_base.py │ │ ├── requirements.txt │ │ └── step_functions_python_stack.py │ └── typescript │ │ ├── apigateway-stack.ts │ │ ├── ecs-fargate-stack.ts │ │ ├── lambda-function-arm-stack.ts │ │ ├── lambda-function-stack.ts │ │ ├── lambda-java-function-stack.ts │ │ ├── lambda-nodejs-function-stack.ts │ │ ├── lambda-provided-arm-stack.ts │ │ ├── lambda-provided-stack.ts │ │ ├── lambda-python-function-stack.ts │ │ ├── lambda-singleton-function-stack.ts │ │ └── step-function-stack.ts └── tsconfig.json ├── package.json ├── scripts ├── fix-version.js ├── generate_third_party_license_file.py ├── publish_prod.sh └── run_integration_tests.sh ├── src ├── apigateway │ ├── README.md │ ├── index.ts │ └── parameters.ts ├── constants.ts ├── datadog-lambda.ts ├── datadog-step-functions.ts ├── ecs │ ├── constants.ts │ ├── environment.ts │ ├── fargate │ │ ├── README.md │ │ ├── constants.ts │ │ ├── datadog-ecs-fargate.ts │ │ ├── environment.ts │ │ ├── interfaces.ts │ │ ├── internal.interfaces.ts │ │ └── utils.ts │ ├── index.ts │ ├── interfaces.ts │ └── utils.ts ├── env.ts ├── forwarder.ts ├── index.ts ├── interfaces.ts ├── layer.ts ├── redirect.ts ├── sample │ ├── ecs_fargate │ │ └── index.ts │ └── lambda │ │ ├── index.ts │ │ ├── index_cdk_v2_test.ts │ │ └── python │ │ └── hello_py.py ├── span-link.ts ├── tag.ts └── transport.ts ├── test ├── assets │ └── Dockerfile ├── datadog-lambda.spec.ts ├── datadog-step-functions.spec.ts ├── ecs │ ├── environment.spec.ts │ ├── fargate │ │ ├── agent.spec.ts │ │ ├── apm-dsd.spec.ts │ │ ├── cws.spec.ts │ │ ├── logging.spec.ts │ │ └── utils.spec.ts │ └── utils.spec.ts ├── env.spec.ts ├── forwarder.spec.ts ├── index.spec.ts ├── lambda │ ├── example-lambda.py │ └── example-lambda.ts ├── layer.spec.ts ├── redirect.spec.ts ├── span-link.spec.ts ├── tags.spec.ts ├── test-utils.ts └── transport.spec.ts ├── tsconfig.dev.json ├── tsconfig.eslint.json ├── tsconfig.jest.json ├── version.json └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | * text=auto eol=lf 4 | *.snap linguist-generated 5 | /.eslintrc.json linguist-generated 6 | /.gitattributes linguist-generated 7 | /.github/workflows/pull-request-lint.yml linguist-generated 8 | /.github/workflows/upgrade.yml linguist-generated 9 | /.gitignore linguist-generated 10 | /.npmignore linguist-generated 11 | /.projen/** linguist-generated 12 | /.projen/deps.json linguist-generated 13 | /.projen/files.json linguist-generated 14 | /.projen/tasks.json linguist-generated 15 | /dist/go/** linguist-generated 16 | /LICENSE linguist-generated 17 | /package.json linguist-generated 18 | /tsconfig.dev.json linguist-generated 19 | /yarn.lock linguist-generated -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @DataDog/serverless-onboarding-enablement 2 | 3 | # Documentation 4 | *.md @DataDog/documentation 5 | 6 | # ECS 7 | examples/ecs @DataDog/container-platform 8 | src/ecs @DataDog/container-platform 9 | src/sample/ecs_fargate @DataDog/container-platform 10 | test/ecs @DataDog/container-platform -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve 4 | --- 5 | 6 | ## Expected Behavior 7 | 8 | 9 | ## Actual Behavior 10 | 11 | 12 | ## Steps to Reproduce the Problem 13 | 14 | 1. 15 | 1. 16 | 1. 17 | 18 | ## Specifications 19 | 20 | - Datadog Lambda Layer version: 21 | - Node version: 22 | 23 | ## Stacktrace 24 | 25 | ``` 26 | Paste here 27 | ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea 4 | --- 5 | 6 | ## Expected Behavior 7 | 8 | 9 | ## Actual Behavior 10 | 11 | 12 | ## Steps to Reproduce the Problem 13 | 14 | 1. 15 | 1. 16 | 1. 17 | 18 | ## Specifications 19 | 20 | - Datadog Lambda Layer version: 21 | - Node version: 22 | 23 | ## Stacktrace 24 | 25 | ``` 26 | Paste here 27 | ``` -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### What does this PR do? 4 | 5 | 6 | 7 | ### Motivation 8 | 9 | 10 | 11 | ### Testing Guidelines 12 | 13 | 14 | 15 | ### Additional Notes 16 | 17 | 18 | 19 | ### Types of Changes 20 | 21 | - [ ] Bug fix 22 | - [ ] New feature 23 | - [ ] Breaking change 24 | - [ ] Misc (docs, refactoring, dependency upgrade, etc.) 25 | 26 | ### Check all that apply 27 | 28 | - [ ] This PR's description is comprehensive 29 | - [ ] This PR contains breaking changes that are documented in the description 30 | - [ ] This PR introduces new APIs or parameters that are documented and unlikely to change in the foreseeable future 31 | - [ ] This PR impacts documentation, and it has been updated (or a ticket has been logged) 32 | - [ ] This PR's changes are covered by the automated tests 33 | - [ ] This PR collects user input/sensitive content into Datadog 34 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: push 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | max-parallel: 4 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | 14 | - name: Set up Node 18 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: 18 18 | 19 | - name: Cache Node modules 20 | id: cache-node-modules 21 | uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1 22 | with: 23 | path: "**/node_modules" 24 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}-${{ matrix.working-dir }} 25 | 26 | - name: Install dependencies 27 | if: steps.cache-node-modules.outputs.cache-hit != 'true' 28 | run: yarn install 29 | 30 | - name: Synthesize project files 31 | run: npx projen 32 | 33 | - name: Anti-tamper check 34 | run: |- 35 | if ! git diff --exit-code; then 36 | echo "Do not directly edit the project files generated by Projen. Add your changes to '.projenrc.js' then run 'npx projen'." 37 | exit 1 38 | fi 39 | 40 | - name: Check formatting 41 | run: yarn check-formatting 42 | 43 | - name: Lint 44 | run: yarn eslint 45 | 46 | test: 47 | runs-on: ubuntu-latest 48 | strategy: 49 | max-parallel: 4 50 | matrix: 51 | node-version: [18, 20] 52 | 53 | steps: 54 | - name: Checkout 55 | uses: actions/checkout@v2 56 | 57 | - name: Set up Node ${{ matrix.node-version }} 58 | uses: actions/setup-node@v1 59 | with: 60 | node-version: ${{ matrix.node-version }} 61 | 62 | - name: Cache Node modules 63 | id: cache-node-modules 64 | uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1 65 | with: 66 | path: "**/node_modules" 67 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}-${{ matrix.working-dir }} 68 | 69 | - name: Install common dependencies 70 | working-directory: ./ 71 | run: yarn install 72 | 73 | - name: Install dependencies 74 | if: steps.cache-node-modules.outputs.cache-hit != 'true' 75 | run: yarn install 76 | 77 | - name: Build 78 | run: yarn build 79 | 80 | - name: Authenticate Docker to Amazon ECR 81 | env: 82 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 83 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 84 | run: aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws 85 | 86 | - name: Run tests 87 | run: yarn test 88 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '40 19 * * 4' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript', 'python' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v2 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v2 71 | -------------------------------------------------------------------------------- /.github/workflows/integration_tests.yml: -------------------------------------------------------------------------------- 1 | name: integration-tests 2 | 3 | on: 4 | push: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | integration-tests: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | max-parallel: 4 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | 16 | - name: Set up Node 18 17 | uses: actions/setup-node@v2 18 | with: 19 | node-version: 18 20 | 21 | - name: Cache Node modules 22 | id: cache-node-modules 23 | uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1 24 | with: 25 | path: "**/node_modules" 26 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}-${{ matrix.working-dir }} 27 | 28 | - name: Install dependencies 29 | if: steps.cache-node-modules.outputs.cache-hit != 'true' 30 | run: yarn install 31 | 32 | - name: Build 33 | run: yarn build 34 | 35 | - name: Install CDK CLI 36 | run: sudo yarn global add aws-cdk --prefix /usr/local 37 | 38 | - name: Install Packages 39 | run: npx projen 40 | 41 | - name: Run tests 42 | env: 43 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 44 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 45 | run: ./scripts/run_integration_tests.sh 46 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-lint.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: pull-request-lint 4 | on: 5 | pull_request_target: 6 | types: 7 | - labeled 8 | - opened 9 | - synchronize 10 | - reopened 11 | - ready_for_review 12 | - edited 13 | merge_group: {} 14 | jobs: 15 | validate: 16 | name: Validate PR title 17 | runs-on: ubuntu-latest 18 | permissions: 19 | pull-requests: write 20 | if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') 21 | steps: 22 | - uses: amannn/action-semantic-pull-request@v5.4.0 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | with: 26 | types: |- 27 | feat 28 | fix 29 | chore 30 | requireScope: false 31 | -------------------------------------------------------------------------------- /.github/workflows/upgrade.yml: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | 3 | name: upgrade 4 | on: 5 | workflow_dispatch: {} 6 | schedule: 7 | - cron: 0 0 * * 1 8 | jobs: 9 | upgrade: 10 | name: Upgrade 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: read 14 | outputs: 15 | patch_created: ${{ steps.create_patch.outputs.patch_created }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | - name: Setup Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: 18.18.0 23 | - name: Install dependencies 24 | run: yarn install --check-files --frozen-lockfile 25 | - name: Upgrade dependencies 26 | run: npx projen upgrade 27 | - name: Find mutations 28 | id: create_patch 29 | run: |- 30 | git add . 31 | git diff --staged --patch --exit-code > repo.patch || echo "patch_created=true" >> $GITHUB_OUTPUT 32 | working-directory: ./ 33 | - name: Upload patch 34 | if: steps.create_patch.outputs.patch_created 35 | uses: actions/upload-artifact@v4.4.0 36 | with: 37 | name: repo.patch 38 | path: repo.patch 39 | overwrite: true 40 | pr: 41 | name: Create Pull Request 42 | needs: upgrade 43 | runs-on: ubuntu-latest 44 | permissions: 45 | contents: read 46 | if: ${{ needs.upgrade.outputs.patch_created }} 47 | steps: 48 | - name: Generate token 49 | id: generate_token 50 | uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 51 | with: 52 | app-id: ${{ secrets.GH_APP_ID }} 53 | private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} 54 | - name: Checkout 55 | uses: actions/checkout@v4 56 | - name: Download patch 57 | uses: actions/download-artifact@v4 58 | with: 59 | name: repo.patch 60 | path: ${{ runner.temp }} 61 | - name: Apply patch 62 | run: '[ -s ${{ runner.temp }}/repo.patch ] && git apply ${{ runner.temp }}/repo.patch || echo "Empty patch. Skipping."' 63 | - name: Set git identity 64 | run: |- 65 | git config user.name "github-actions" 66 | git config user.email "github-actions@github.com" 67 | - name: Create Pull Request 68 | id: create-pr 69 | uses: peter-evans/create-pull-request@v6 70 | with: 71 | token: ${{ steps.generate_token.outputs.token }} 72 | commit-message: |- 73 | chore(deps): upgrade dependencies 74 | 75 | Upgrades project dependencies. See details in [workflow run]. 76 | 77 | [Workflow Run]: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 78 | 79 | ------ 80 | 81 | *Automatically created by projen via the "upgrade" workflow* 82 | branch: github-actions/upgrade 83 | title: "chore(deps): upgrade dependencies" 84 | body: |- 85 | Upgrades project dependencies. See details in [workflow run]. 86 | 87 | [Workflow Run]: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} 88 | 89 | ------ 90 | 91 | *Automatically created by projen via the "upgrade" workflow* 92 | author: github-actions 93 | committer: github-actions 94 | signoff: true 95 | environment: 96 | name: protected-main-env 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | !/.gitattributes 3 | !/.projen/tasks.json 4 | !/.projen/deps.json 5 | !/.projen/files.json 6 | !/.github/workflows/pull-request-lint.yml 7 | !/package.json 8 | !/LICENSE 9 | !/.npmignore 10 | logs 11 | *.log 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | lerna-debug.log* 16 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | lib-cov 22 | coverage 23 | *.lcov 24 | .nyc_output 25 | build/Release 26 | node_modules/ 27 | jspm_packages/ 28 | *.tsbuildinfo 29 | .eslintcache 30 | *.tgz 31 | .yarn-integrity 32 | .cache 33 | *.js 34 | !jest.config.js 35 | !src/sample 36 | !src/sample/lambda_nodejs/hello_node.js 37 | !scripts/fix-version.js 38 | *.d.ts 39 | .cdk.staging 40 | cdk.out/ 41 | .parcel-cache 42 | test/__snapshots__ 43 | .DS_Store 44 | integration_tests/cdk.out 45 | integration_tests/testlib 46 | bin 47 | obj 48 | __pycache__ 49 | /test-reports/ 50 | junit.xml 51 | /coverage/ 52 | !/.github/workflows/upgrade.yml 53 | !/test/ 54 | !/tsconfig.dev.json 55 | !/src/ 56 | /lib 57 | /dist/ 58 | !/.eslintrc.json 59 | .jsii 60 | tsconfig.json 61 | !integration_tests/tsconfig.json 62 | !/.projenrc.js 63 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | !LICENSE 3 | !LICENSE-3rdparty.csv 4 | !NOTICE 5 | /scripts 6 | /integration_tests 7 | .prettierrc 8 | cdk.out/* 9 | yarn-error.log 10 | CHANGELOG.md 11 | CONTRIBUTING.md 12 | /examples 13 | /.projen/ 14 | /test-reports/ 15 | junit.xml 16 | /coverage/ 17 | /test/ 18 | /tsconfig.dev.json 19 | /src/ 20 | !/lib/ 21 | !/lib/**/*.js 22 | !/lib/**/*.d.ts 23 | dist 24 | /tsconfig.json 25 | /.github/ 26 | /.vscode/ 27 | /.idea/ 28 | /.projenrc.js 29 | tsconfig.tsbuildinfo 30 | /.eslintrc.json 31 | !.jsii 32 | /.gitattributes 33 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "trailingComma": "all", 4 | "arrowParens": "always", 5 | "quoteProps": "consistent" 6 | } -------------------------------------------------------------------------------- /.projen/deps.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "name": "@aws-cdk/aws-lambda-python-alpha", 5 | "version": "^2.134.0-alpha.0", 6 | "type": "build" 7 | }, 8 | { 9 | "name": "@stylistic/eslint-plugin", 10 | "version": "^2", 11 | "type": "build" 12 | }, 13 | { 14 | "name": "@types/jest", 15 | "type": "build" 16 | }, 17 | { 18 | "name": "@types/node", 19 | "version": "^18", 20 | "type": "build" 21 | }, 22 | { 23 | "name": "@typescript-eslint/eslint-plugin", 24 | "version": "^8", 25 | "type": "build" 26 | }, 27 | { 28 | "name": "@typescript-eslint/parser", 29 | "version": "^8", 30 | "type": "build" 31 | }, 32 | { 33 | "name": "eslint-config-prettier", 34 | "type": "build" 35 | }, 36 | { 37 | "name": "eslint-import-resolver-typescript", 38 | "type": "build" 39 | }, 40 | { 41 | "name": "eslint-plugin-import", 42 | "type": "build" 43 | }, 44 | { 45 | "name": "eslint-plugin-prettier", 46 | "type": "build" 47 | }, 48 | { 49 | "name": "eslint", 50 | "version": "^9", 51 | "type": "build" 52 | }, 53 | { 54 | "name": "jest", 55 | "type": "build" 56 | }, 57 | { 58 | "name": "jest-junit", 59 | "version": "^16", 60 | "type": "build" 61 | }, 62 | { 63 | "name": "jsii-diff", 64 | "type": "build" 65 | }, 66 | { 67 | "name": "jsii-pacmak", 68 | "type": "build" 69 | }, 70 | { 71 | "name": "jsii-rosetta", 72 | "version": "~5.6.0", 73 | "type": "build" 74 | }, 75 | { 76 | "name": "jsii", 77 | "version": "~5.6.0", 78 | "type": "build" 79 | }, 80 | { 81 | "name": "prettier", 82 | "type": "build" 83 | }, 84 | { 85 | "name": "projen", 86 | "type": "build" 87 | }, 88 | { 89 | "name": "standard-version", 90 | "type": "build" 91 | }, 92 | { 93 | "name": "ts-jest", 94 | "type": "build" 95 | }, 96 | { 97 | "name": "ts-node", 98 | "type": "build" 99 | }, 100 | { 101 | "name": "typescript", 102 | "type": "build" 103 | }, 104 | { 105 | "name": "loglevel", 106 | "type": "bundled" 107 | }, 108 | { 109 | "name": "aws-cdk-lib", 110 | "version": "^2.177.0", 111 | "type": "peer" 112 | }, 113 | { 114 | "name": "constructs", 115 | "version": "^10.0.5", 116 | "type": "peer" 117 | }, 118 | { 119 | "name": "loglevel", 120 | "type": "runtime" 121 | } 122 | ], 123 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 124 | } 125 | -------------------------------------------------------------------------------- /.projen/files.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | ".eslintrc.json", 4 | ".gitattributes", 5 | ".github/workflows/pull-request-lint.yml", 6 | ".github/workflows/upgrade.yml", 7 | ".gitignore", 8 | ".projen/deps.json", 9 | ".projen/files.json", 10 | ".projen/tasks.json", 11 | "LICENSE", 12 | "tsconfig.dev.json" 13 | ], 14 | "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." 15 | } 16 | -------------------------------------------------------------------------------- /.versionrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageFiles": [ 3 | { 4 | "filename": "version.json", 5 | "type": "json" 6 | } 7 | ], 8 | "bumpFiles": [ 9 | { 10 | "filename": "version.json", 11 | "type": "json" 12 | } 13 | ], 14 | "commitAll": true, 15 | "scripts": { 16 | "postbump": "npx projen && git add ." 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-1.22.19.cjs 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We love pull requests. Here's a quick guide. 4 | 5 | _Please refer to the README.md for information about the structure of this repo (note that this repo supports our packages `datadog-cdk-constructs` and `datadog-cdk-constructs-v2`_) 6 | 7 | 1. Fork, clone and branch off `main`: 8 | ```bash 9 | git clone git@github.com:/datadog-cdk-constructs.git 10 | git checkout -b 11 | ``` 12 | 1. Install dependencies with `yarn install`. 13 | 1. Make your changes. 14 | 1. Run unit tests with `yarn test`. 15 | 1. Manually test your changes using CDK commands such as `cdk synth`, `cdk diff`, and `cdk deploy`. 16 | - Please see the [README.md](README.md#testing) for instructions on how to manually test. 17 | 1. Push to your fork and [submit a pull request][pr]. 18 | 19 | [pr]: https://github.com/your-username/datadog-cdk-constructs/compare/DataDog:main...main 20 | 21 | At this point you're waiting on us. We may suggest some changes or improvements or alternatives. 22 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Datadog datadog-cdk-constructs 2 | Copyright 2021 Datadog, Inc. 3 | 4 | This product includes software developed at Datadog (https://www.datadoghq.com/). 5 | -------------------------------------------------------------------------------- /examples/ecs/go-stack/.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | app 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # go.sum should be committed 16 | !go.sum 17 | 18 | # CDK asset staging directory 19 | .cdk.staging 20 | cdk.out 21 | 22 | # The copied Go package for dev testing 23 | ddcdkconstruct/ -------------------------------------------------------------------------------- /examples/ecs/go-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK Go Example 2 | 3 | Use this example Go stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library for ECS Fargate. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 1. Set the Datadog API key in your shell session: `export DD_API_KEY=`. 9 | 1. Synthesize the CloudFormation template: `cdk synth`. 10 | 1. Review the proposed resource and permission changes: `cdk diff`. 11 | 1. Deploy the stack to AWS: `cdk deploy`. 12 | 1. Invoke your ECS Task Defintions and verify data in [Datadog](https://app.datadoghq.com/) (metrics, traces, logs, orchestrator explorer, etc). 13 | 14 | ## Testing 15 | 16 | 1. Run `yarn build` to create the Python package. 17 | 2. Copy your local module: `cp -r dist/go/ddcdkconstruct examples/ecs/go-stack`. 18 | 3. Navigate to the example stack: `cd examples/ecs/go-stack`. 19 | 4. In `go.mod` change the version of the dependency `ddcdkconstruct`: 20 | 21 | ```go 22 | require( 23 | ... 24 | github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2 v2.0.0-unpublished 25 | ) 26 | ``` 27 | 28 | 5. Run the following commands to replace the import with the local path of the module 29 | 30 | ```go 31 | go mod edit -replace=github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2@v2.0.0-unpublished=./ddcdkconstruct 32 | go get -d github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2@v2.0.0-unpublished 33 | ``` 34 | 35 | 6. Install dependencies: `go get`. 36 | 7. Review the proposed resource and permission changes: `cdk diff`. 37 | 8. Deploy the stack to AWS: `cdk deploy`. 38 | 9. Invoke your ECS Task Defintions and verify data in [Datadog](https://app.datadoghq.com/). 39 | 40 | ## Resources 41 | 42 | This demo project was created and modified from [Tutorial: Create your first AWS CDK app](https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html) 43 | -------------------------------------------------------------------------------- /examples/ecs/go-stack/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2" 7 | "github.com/aws/aws-cdk-go/awscdk/v2" 8 | "github.com/aws/aws-cdk-go/awscdk/v2/awsecs" 9 | "github.com/aws/constructs-go/constructs/v10" 10 | "github.com/aws/jsii-runtime-go" 11 | ) 12 | 13 | type AppStackProps struct { 14 | awscdk.StackProps 15 | } 16 | 17 | // Creates a stack with Datadog instrumentation for ECS Fargate 18 | func NewAppStackWithDatadogFargate(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { 19 | // Setup stack 20 | var sprops awscdk.StackProps 21 | if props != nil { 22 | sprops = props.StackProps 23 | } 24 | stack := awscdk.NewStack(scope, &id, &sprops) 25 | 26 | // Set up Datadog integration 27 | datadog := ddcdkconstruct.NewDatadogECSFargate( 28 | &ddcdkconstruct.DatadogECSFargateProps{ 29 | ApiKey: jsii.String(os.Getenv("DD_API_KEY")), 30 | }, 31 | ) 32 | task := datadog.FargateTaskDefinition( 33 | stack, 34 | jsii.String("DatadogGolangTask"), 35 | &awsecs.FargateTaskDefinitionProps{}, 36 | &ddcdkconstruct.DatadogECSFargateProps{}, 37 | ) 38 | task.AddContainer( 39 | jsii.String("DummyDogstatsd"), 40 | &awsecs.ContainerDefinitionOptions{ 41 | Image: awsecs.ContainerImage_FromRegistry( 42 | jsii.String("ghcr.io/datadog/apps-dogstatsd:main"), 43 | &awsecs.RepositoryImageProps{}, 44 | ), 45 | }, 46 | ) 47 | 48 | return stack 49 | } 50 | 51 | func main() { 52 | defer jsii.Close() 53 | 54 | app := awscdk.NewApp(nil) 55 | 56 | NewAppStackWithDatadogFargate(app, "CdkGoStack", &AppStackProps{ 57 | awscdk.StackProps{ 58 | Env: env(), 59 | }, 60 | }) 61 | 62 | app.Synth(nil) 63 | } 64 | 65 | // env determines the AWS environment (account+region) in which our stack is to 66 | // be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html 67 | func env() *awscdk.Environment { 68 | env := awscdk.Environment{ 69 | Account: jsii.String("376334461865"), 70 | Region: jsii.String("us-east-1"), 71 | } 72 | return &env 73 | } 74 | -------------------------------------------------------------------------------- /examples/ecs/go-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "go mod download && go run app.go", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "go.mod", 11 | "go.sum", 12 | "**/*test.go" 13 | ] 14 | }, 15 | "context": { 16 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 17 | "@aws-cdk/core:checkSecretUsage": true, 18 | "@aws-cdk/core:target-partitions": [ 19 | "aws", 20 | "aws-cn" 21 | ], 22 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 23 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 24 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 25 | "@aws-cdk/aws-iam:minimizePolicies": true, 26 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 27 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 28 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 29 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 30 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 31 | "@aws-cdk/core:enablePartitionLiterals": true, 32 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 33 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 34 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 35 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 36 | "@aws-cdk/aws-route53-patters:useCertificate": true, 37 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 38 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 39 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 40 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 41 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 42 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 43 | "@aws-cdk/aws-redshift:columnId": true, 44 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 45 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 46 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 47 | "@aws-cdk/aws-kms:aliasNameRef": true, 48 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 49 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 50 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 51 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 52 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 53 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 54 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 55 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 56 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, 57 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, 58 | "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, 59 | "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, 60 | "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, 61 | "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, 62 | "@aws-cdk/aws-eks:nodegroupNameAttribute": true, 63 | "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, 64 | "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, 65 | "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, 66 | "@aws-cdk/aws-stepfunctions-tasks:ecsReduceRunTaskPermissions": true 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/ecs/go-stack/go.mod: -------------------------------------------------------------------------------- 1 | module app 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.1 6 | 7 | require ( 8 | github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2 v2.0.0 9 | github.com/aws/aws-cdk-go/awscdk/v2 v2.177.0 10 | github.com/aws/constructs-go/constructs/v10 v10.4.2 11 | github.com/aws/jsii-runtime-go v1.110.0 12 | ) 13 | 14 | require ( 15 | github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct v1.24.0 // indirect 16 | github.com/Masterminds/semver/v3 v3.3.1 // indirect 17 | github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.228 // indirect 18 | github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.4 // indirect 19 | github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv6/v2 v2.1.0 // indirect 20 | github.com/cdklabs/cloud-assembly-schema-go/awscdkcloudassemblyschema/v39 v39.2.20 // indirect 21 | github.com/fatih/color v1.18.0 // indirect 22 | github.com/mattn/go-colorable v0.1.13 // indirect 23 | github.com/mattn/go-isatty v0.0.20 // indirect 24 | github.com/yuin/goldmark v1.4.13 // indirect 25 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 26 | golang.org/x/mod v0.24.0 // indirect 27 | golang.org/x/sync v0.12.0 // indirect 28 | golang.org/x/sys v0.31.0 // indirect 29 | golang.org/x/tools v0.31.0 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /examples/ecs/python-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK Python Example 2 | 3 | Use this example Python stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 1. Set the Datadog API key in your shell session: `export DD_API_KEY=`. 9 | 1. Create a virtual environment: `virtualenv env` 10 | 1. Activate the virtual environment: `source env/bin/activate` 11 | 1. Install dependencies: `pip install -r requirements.txt` 12 | 1. Review the resource and permission changes: `cdk diff`. 13 | 1. Deploy the stack to AWS: `cdk deploy`. 14 | 1. Invoke your ECS Task Defintions and verify data in [Datadog](https://app.datadoghq.com/) (metrics, traces, logs, orchestrator explorer, etc.). 15 | 16 | ## Testing 17 | 18 | When updating the Datadog CDK package and testing with a Python example, follow the steps below to test locally: 19 | 20 | 1. Run `yarn build` to create the Python package. 21 | 1. Copy the local module: `cp dist/python/datadog_cdk_constructs_v2-$VERSION.tar.gz examples/ecs/python-stack`. 22 | 1. Navigate to the example stack directory: `cd examples/ecs/python-stack`. 23 | 1. Create a virtual environment: `virtualenv env && source env/bin/activate`. 24 | 1. Install dependencies: `pip install -r requirements.txt`. 25 | 1. Install your local module: `pip install ./datadog_cdk_constructs_v2-$VERSION.tar.gz`. 26 | 1. View your updated YAML task definition: `cdk synth`. 27 | 1. Deploy your updated resources: `cdk deploy`. 28 | -------------------------------------------------------------------------------- /examples/ecs/python-stack/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from aws_cdk import App 3 | from cdk_python.cdk_python_stack import CdkPythonStack 4 | 5 | app = App() 6 | CdkPythonStack(app, "CdkPythonStack") 7 | 8 | app.synth() 9 | -------------------------------------------------------------------------------- /examples/ecs/python-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "python3 app.py", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "requirements.txt", 11 | "__pycache__" 12 | ] 13 | }, 14 | "context": { 15 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 16 | "@aws-cdk/core:checkSecretUsage": true, 17 | "@aws-cdk/core:target-partitions": [ 18 | "aws", 19 | "aws-cn" 20 | ], 21 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 22 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 23 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 24 | "@aws-cdk/aws-iam:minimizePolicies": true, 25 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 26 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 27 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 28 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 29 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 30 | "@aws-cdk/core:enablePartitionLiterals": true, 31 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 32 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 33 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true 34 | } 35 | } -------------------------------------------------------------------------------- /examples/ecs/python-stack/cdk_python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataDog/datadog-cdk-constructs/5ca6da122a1059e215a51151f3efa2789810500b/examples/ecs/python-stack/cdk_python/__init__.py -------------------------------------------------------------------------------- /examples/ecs/python-stack/cdk_python/cdk_python_stack.py: -------------------------------------------------------------------------------- 1 | from constructs import Construct 2 | from datadog_cdk_constructs_v2 import DatadogECSFargate, Cardinality 3 | from aws_cdk import Stack 4 | from aws_cdk import aws_ecs as ecs 5 | import os 6 | 7 | class CdkPythonStack(Stack): 8 | def __init__(self, scope: Construct, id: str, **kwargs) -> None: 9 | super().__init__(scope, id, **kwargs) 10 | 11 | ecsDatadog = DatadogECSFargate( 12 | api_key=os.getenv("DD_API_KEY"), 13 | dogstatsd={ 14 | "dogstatsd_cardinality": Cardinality.HIGH, 15 | "is_origin_detection_enabled": True, 16 | }, 17 | global_tags="owner:datadog, team:contp", 18 | ) 19 | 20 | task = ecsDatadog.fargate_task_definition(self, "PythonFargateTask") 21 | 22 | task.add_container( 23 | id = "dogstatsd-app", 24 | image = ecs.ContainerImage.from_registry("ghcr.io/datadog/apps-dogstatsd:main"), 25 | ) 26 | -------------------------------------------------------------------------------- /examples/ecs/python-stack/requirements.txt: -------------------------------------------------------------------------------- 1 | aws-cdk-lib~=2.177.0 2 | aws-cdk.aws-lambda-go-alpha~=2.134.0a0 3 | constructs~=10.0.5 4 | datadog_cdk_constructs_v2~=2.0.0 5 | -------------------------------------------------------------------------------- /examples/ecs/typescript-stack/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /examples/ecs/typescript-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK TypeScript Example 2 | 3 | Use this example TypeScript stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 1. Set the Datadog API key in your shell session: `export DD_API_KEY=`. 9 | 1. Install dependencies: `yarn`. 10 | 1. Synthesize the CloudFormation template: `cdk synth`. 11 | 1. Review the proposed resource and permission changes: `cdk diff`. 12 | 1. Deploy the stack to AWS: `cdk deploy`. 13 | 1. Execute your Task Definitions and verify data in [Datadog](https://app.datadoghq.com/) (metrics, traces, logs, orchestrator explorer, etc.) 14 | 15 | ## Testing 16 | 17 | 1. Run `yarn build` to create the TypeScript package. 18 | 1. Set the version as an environment variable for convenience: `VERSION=2.x.x` 19 | 1. Copy the local module: `cp dist/js/datadog-cdk-constructs-v2@$VERSION.jsii.tgz examples/ecs/typescript-stack/datadog-cdk-constructs-v2-$VERSION.jsii.tgz`. 20 | 1. Navigate to the example stack: `cd examples/ecs/typescript-stack`. 21 | 1. Install your local module: `yarn add file:./datadog-cdk-constructs-v2-$VERSION.jsii.tgz`. 22 | 1. Install project dependencies: `yarn install`. 23 | 1. View your updated YAML task definition: `cdk synth`. 24 | 1. Deploy the updated resources: `cdk deploy`. 25 | -------------------------------------------------------------------------------- /examples/ecs/typescript-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/index.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules" 16 | ] 17 | }, 18 | "context": { 19 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 20 | "@aws-cdk/core:checkSecretUsage": true, 21 | "@aws-cdk/core:target-partitions": [ 22 | "aws", 23 | "aws-cn" 24 | ], 25 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 26 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 27 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 28 | "@aws-cdk/aws-iam:minimizePolicies": true, 29 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 30 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 31 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 32 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 33 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 34 | "@aws-cdk/core:enablePartitionLiterals": true, 35 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 36 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 37 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/ecs/typescript-stack/lib/cdk-typescript-stack.ts: -------------------------------------------------------------------------------- 1 | import { Stack, StackProps } from "aws-cdk-lib"; 2 | import { ContainerImage } from "aws-cdk-lib/aws-ecs"; 3 | import { Construct } from "constructs"; 4 | import { DatadogECSFargate } from "datadog-cdk-constructs-v2"; 5 | 6 | export class CdkTypeScriptStack extends Stack { 7 | constructor(scope: Construct, id: string, props?: StackProps) { 8 | super(scope, id, props); 9 | 10 | console.log("Instrumenting ECS Task Definitions in TypeScript stack with Datadog"); 11 | 12 | // Configure the Datadog ECS Fargate construct 13 | const ecsDatadog = new DatadogECSFargate({ 14 | apiKey: process.env.DD_API_KEY_SECRET, 15 | isDatadogDependencyEnabled: true, 16 | environmentVariables: { 17 | DD_TAGS: "team:cont-p, owner:container-monitoring", 18 | }, 19 | dogstatsd: { 20 | isEnabled: true, 21 | }, 22 | apm: { 23 | isEnabled: true, 24 | }, 25 | logCollection: { 26 | isEnabled: true, 27 | fluentbitConfig: { 28 | logDriverConfig: { 29 | serviceName: "datadog-cdk-test", 30 | sourceName: "datadog-cdk-test", 31 | }, 32 | }, 33 | }, 34 | env: "staging", 35 | version: "v1.0.0", 36 | service: "container-service", 37 | }); 38 | 39 | // Create a Datadog ECS Fargate task definition 40 | const fargateTaskDefinition = ecsDatadog.fargateTaskDefinition(this, "TypescriptFargateTask", { 41 | memoryLimitMiB: 1024, 42 | }); 43 | 44 | fargateTaskDefinition.addContainer("DogstatsdApp", { 45 | containerName: "datadog-dogstatsd-app", 46 | image: ContainerImage.fromRegistry("ghcr.io/datadog/apps-dogstatsd:main"), 47 | essential: false, 48 | }); 49 | 50 | fargateTaskDefinition.addContainer("DatadogAPM", { 51 | containerName: "datadog-apm-app", 52 | image: ContainerImage.fromRegistry("ghcr.io/datadog/apps-tracegen:main"), 53 | essential: true, 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/ecs/typescript-stack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-stack", 3 | "version": "1.0.0", 4 | "bin": { 5 | "cdk-typescript": "bin/index.js" 6 | }, 7 | "devDependencies": { 8 | "@types/node": "^20.8.8", 9 | "aws-cdk": "^2.134.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "~5.2.2" 12 | }, 13 | "dependencies": { 14 | "@aws-cdk/aws-lambda-go-alpha": "^2.134.0-alpha.0", 15 | "@aws-cdk/aws-lambda-python-alpha": "^2.134.0-alpha.0", 16 | "aws-cdk-lib": "^2.187.0", 17 | "constructs": "^10.3.0", 18 | "datadog-cdk-constructs-v2": "file:./datadog-cdk-constructs-v2-2.2.0.jsii.tgz" 19 | } 20 | } -------------------------------------------------------------------------------- /examples/go-stack/.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | app 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # go.sum should be committed 16 | !go.sum 17 | 18 | # CDK asset staging directory 19 | .cdk.staging 20 | cdk.out 21 | 22 | # The copied Go package for dev testing 23 | ddcdkconstruct/ -------------------------------------------------------------------------------- /examples/go-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK Go Example 2 | 3 | Use this example Go stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library. It contains Node, Python, and Go Lambda functions. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 1. Run `export DD_API_KEY=` to set the Datadog API key in your shell session. 9 | 1. Run `cdk synth` to synthesize the CloudFormation template. 10 | 1. Run `cdk diff` to see the resource and permission changes that are made. 11 | 1. Run `cdk deploy` to deploy the stack to AWS. 12 | 1. Invoke your Lambda functions and look for them in [Datadog Serverless Monitoring](https://app.datadoghq.com/functions?cloud=aws). 13 | 14 | ![Image 2023-11-02 at 11 44 22 AM](https://github.com/DataDog/datadog-cdk-constructs/assets/35278470/9c7b7b15-27ff-4de1-8f54-f5c352f1774b) 15 | 16 | ## Resources 17 | 18 | This demo project was created and modified from [Tutorial: Create your first AWS CDK app](https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html) 19 | -------------------------------------------------------------------------------- /examples/go-stack/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2" 7 | "github.com/aws/aws-cdk-go/awscdk/v2" 8 | "github.com/aws/aws-cdk-go/awscdk/v2/awslambda" 9 | "github.com/aws/constructs-go/constructs/v10" 10 | "github.com/aws/jsii-runtime-go" 11 | ) 12 | 13 | type AppStackProps struct { 14 | awscdk.StackProps 15 | } 16 | 17 | // Creates a stack without Datadog integration 18 | func NewAppStackWithoutDatadog(scope constructs.Construct, id *string, props *AppStackProps) (awscdk.Stack, awslambda.Function) { 19 | var sprops awscdk.StackProps 20 | if props != nil { 21 | sprops = props.StackProps 22 | } 23 | stack := awscdk.NewStack(scope, id, &sprops) 24 | 25 | myFunction := awslambda.NewFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.FunctionProps{ 26 | Runtime: awslambda.Runtime_NODEJS_20_X(), 27 | Handler: jsii.String("index.handler"), 28 | Code: awslambda.Code_FromInline(jsii.String(` 29 | exports.handler = async function(event) { 30 | return { 31 | statusCode: 200, 32 | body: JSON.stringify('Hello World!'), 33 | }; 34 | }; 35 | `)), 36 | }) 37 | 38 | // Define the Lambda function URL resource 39 | myFunctionUrl := myFunction.AddFunctionUrl(&awslambda.FunctionUrlOptions{ 40 | AuthType: awslambda.FunctionUrlAuthType_NONE, 41 | }) 42 | 43 | // Define a CloudFormation output for your URL 44 | awscdk.NewCfnOutput(stack, jsii.String("myFunctionUrlOutput"), &awscdk.CfnOutputProps{ 45 | Value: myFunctionUrl.Url(), 46 | }) 47 | 48 | return stack, myFunction 49 | } 50 | 51 | // Creates a stack with Datadog integration set up, using the new API (DatadogLambda, DatadogLambdaProps) 52 | func NewAppStackWithDatadogLambda(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { 53 | stack, lambdaFunction := NewAppStackWithoutDatadog(scope, &id, props) 54 | 55 | // Set up Datadog integration 56 | datadog := ddcdkconstruct.NewDatadogLambda( 57 | stack, 58 | jsii.String("Datadog"), 59 | &ddcdkconstruct.DatadogLambdaProps{ 60 | NodeLayerVersion: jsii.Number(113), 61 | PythonLayerVersion: jsii.Number(97), 62 | JavaLayerVersion: jsii.Number(21), 63 | DotnetLayerVersion: jsii.Number(15), 64 | AddLayers: jsii.Bool(true), 65 | ExtensionLayerVersion: jsii.Number(62), 66 | FlushMetricsToLogs: jsii.Bool(true), 67 | Site: jsii.String("datadoghq.com"), 68 | ApiKey: jsii.String(os.Getenv("DD_API_KEY")), 69 | EnableDatadogTracing: jsii.Bool(true), 70 | EnableMergeXrayTraces: jsii.Bool(true), 71 | EnableDatadogLogs: jsii.Bool(true), 72 | InjectLogContext: jsii.Bool(true), 73 | LogLevel: jsii.String("debug"), 74 | }) 75 | datadog.AddLambdaFunctions(&[]interface{}{lambdaFunction}, nil) 76 | 77 | return stack 78 | } 79 | 80 | func main() { 81 | defer jsii.Close() 82 | 83 | app := awscdk.NewApp(nil) 84 | 85 | NewAppStackWithDatadogLambda(app, "CdkGoStack", &AppStackProps{ 86 | awscdk.StackProps{ 87 | Env: env(), 88 | }, 89 | }) 90 | 91 | app.Synth(nil) 92 | } 93 | 94 | // env determines the AWS environment (account+region) in which our stack is to 95 | // be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html 96 | func env() *awscdk.Environment { 97 | env := awscdk.Environment{ 98 | Account: jsii.String("425362996713"), 99 | Region: jsii.String("sa-east-1"), 100 | } 101 | return &env 102 | } 103 | -------------------------------------------------------------------------------- /examples/go-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "go mod download && go run app.go", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "go.mod", 11 | "go.sum", 12 | "**/*test.go" 13 | ] 14 | }, 15 | "context": { 16 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 17 | "@aws-cdk/core:checkSecretUsage": true, 18 | "@aws-cdk/core:target-partitions": [ 19 | "aws", 20 | "aws-cn" 21 | ], 22 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 23 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 24 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 25 | "@aws-cdk/aws-iam:minimizePolicies": true, 26 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 27 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 28 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 29 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 30 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 31 | "@aws-cdk/core:enablePartitionLiterals": true, 32 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 33 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 34 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 35 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 36 | "@aws-cdk/aws-route53-patters:useCertificate": true, 37 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 38 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 39 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 40 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 41 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 42 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 43 | "@aws-cdk/aws-redshift:columnId": true, 44 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 45 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 46 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 47 | "@aws-cdk/aws-kms:aliasNameRef": true, 48 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 49 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 50 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 51 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 52 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 53 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 54 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 55 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 56 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, 57 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, 58 | "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, 59 | "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, 60 | "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, 61 | "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, 62 | "@aws-cdk/aws-eks:nodegroupNameAttribute": true, 63 | "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, 64 | "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, 65 | "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, 66 | "@aws-cdk/aws-stepfunctions-tasks:ecsReduceRunTaskPermissions": true 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/go-stack/go.mod: -------------------------------------------------------------------------------- 1 | module app 2 | 3 | go 1.22.0 4 | 5 | toolchain go1.22.5 6 | 7 | require ( 8 | github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2 v2.0.0 9 | github.com/aws/aws-cdk-go/awscdk/v2 v2.151.0 10 | github.com/aws/constructs-go/constructs/v10 v10.3.0 11 | github.com/aws/jsii-runtime-go v1.106.0 12 | ) 13 | 14 | require ( 15 | github.com/Masterminds/semver/v3 v3.3.1 // indirect 16 | github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.220 // indirect 17 | github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.3 // indirect 18 | github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv6/v2 v2.1.0 // indirect 19 | github.com/fatih/color v1.18.0 // indirect 20 | github.com/mattn/go-colorable v0.1.13 // indirect 21 | github.com/mattn/go-isatty v0.0.20 // indirect 22 | github.com/yuin/goldmark v1.4.13 // indirect 23 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 24 | golang.org/x/mod v0.22.0 // indirect 25 | golang.org/x/sync v0.10.0 // indirect 26 | golang.org/x/sys v0.28.0 // indirect 27 | golang.org/x/tools v0.28.0 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /examples/lambda/dotnet/Handler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net; 4 | using Amazon.Lambda.Core; 5 | using Amazon.Lambda.APIGatewayEvents; 6 | using Newtonsoft.Json; 7 | 8 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 9 | [assembly: LambdaSerializer( 10 | typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] 11 | 12 | namespace HelloWorld 13 | { 14 | public class Handler 15 | { 16 | 17 | public APIGatewayProxyResponse SayHi(APIGatewayProxyRequest request, ILambdaContext context) 18 | { 19 | APIGatewayProxyResponse response; 20 | Dictionary dict = new Dictionary(); 21 | dict.Add("hello", "world"); 22 | response = CreateResponse(dict); 23 | return response; 24 | } 25 | 26 | APIGatewayProxyResponse CreateResponse(IDictionary result) 27 | { 28 | int statusCode = (result != null) ? 29 | (int)HttpStatusCode.OK : 30 | (int)HttpStatusCode.InternalServerError; 31 | 32 | string body = (result != null) ? 33 | JsonConvert.SerializeObject(result) : string.Empty; 34 | 35 | var response = new APIGatewayProxyResponse 36 | { 37 | StatusCode = statusCode, 38 | Body = body, 39 | Headers = new Dictionary 40 | { 41 | { "Content-Type", "application/json" }, 42 | { "Access-Control-Allow-Origin", "*" } 43 | } 44 | }; 45 | 46 | return response; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/lambda/dotnet/HelloWorld.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | Lambda 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/lambda/go/go.mod: -------------------------------------------------------------------------------- 1 | module example.com/cdk-example 2 | 3 | go 1.21 4 | toolchain go1.24.1 5 | 6 | require github.com/aws/aws-lambda-go v1.41.0 7 | 8 | require ( 9 | github.com/DataDog/appsec-internal-go v1.2.0 // indirect 10 | github.com/DataDog/datadog-agent/pkg/obfuscate v0.49.0 // indirect 11 | github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.49.0 // indirect 12 | github.com/DataDog/datadog-agent/pkg/util/log v0.49.0 // indirect 13 | github.com/DataDog/datadog-agent/pkg/util/scrubber v0.49.0 // indirect 14 | github.com/DataDog/datadog-go/v5 v5.3.0 // indirect 15 | github.com/DataDog/go-libddwaf/v2 v2.2.1 // indirect 16 | github.com/DataDog/go-tuf v1.0.2-0.5.2 // indirect 17 | github.com/DataDog/sketches-go v1.4.3 // indirect 18 | github.com/Microsoft/go-winio v0.6.1 // indirect 19 | github.com/andybalholm/brotli v1.0.6 // indirect 20 | github.com/aws/aws-sdk-go v1.48.11 // indirect 21 | github.com/aws/aws-sdk-go-v2 v1.23.5 // indirect 22 | github.com/aws/aws-sdk-go-v2/config v1.25.11 // indirect 23 | github.com/aws/aws-sdk-go-v2/credentials v1.16.9 // indirect 24 | github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9 // indirect 25 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8 // indirect 26 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8 // indirect 27 | github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 // indirect 28 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3 // indirect 29 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8 // indirect 30 | github.com/aws/aws-sdk-go-v2/service/kms v1.27.2 // indirect 31 | github.com/aws/aws-sdk-go-v2/service/sso v1.18.2 // indirect 32 | github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.2 // indirect 33 | github.com/aws/aws-sdk-go-v2/service/sts v1.26.2 // indirect 34 | github.com/aws/aws-xray-sdk-go v1.8.3 // indirect 35 | github.com/aws/smithy-go v1.18.1 // indirect 36 | github.com/cenkalti/backoff/v4 v4.2.1 // indirect 37 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 38 | github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect 39 | github.com/dustin/go-humanize v1.0.1 // indirect 40 | github.com/ebitengine/purego v0.5.1 // indirect 41 | github.com/golang/protobuf v1.5.3 // indirect 42 | github.com/google/uuid v1.4.0 // indirect 43 | github.com/hashicorp/errwrap v1.1.0 // indirect 44 | github.com/hashicorp/go-multierror v1.1.1 // indirect 45 | github.com/jmespath/go-jmespath v0.4.0 // indirect 46 | github.com/klauspost/compress v1.17.4 // indirect 47 | github.com/outcaste-io/ristretto v0.2.3 // indirect 48 | github.com/philhofer/fwd v1.1.2 // indirect 49 | github.com/pkg/errors v0.9.1 // indirect 50 | github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect 51 | github.com/sony/gobreaker v0.5.0 // indirect 52 | github.com/tinylib/msgp v1.1.9 // indirect 53 | github.com/valyala/bytebufferpool v1.0.0 // indirect 54 | github.com/valyala/fasthttp v1.51.0 // indirect 55 | go.uber.org/atomic v1.11.0 // indirect 56 | go4.org/intern v0.0.0-20230525184215-6c62f75575cb // indirect 57 | go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect 58 | golang.org/x/mod v0.17.0 // indirect 59 | golang.org/x/net v0.38.0 // indirect 60 | golang.org/x/sync v0.12.0 // indirect 61 | golang.org/x/sys v0.31.0 // indirect 62 | golang.org/x/text v0.23.0 // indirect 63 | golang.org/x/time v0.5.0 // indirect 64 | golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect 65 | google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect 66 | google.golang.org/grpc v1.59.0 // indirect 67 | google.golang.org/protobuf v1.33.0 // indirect 68 | gopkg.in/yaml.v2 v2.4.0 // indirect 69 | inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a // indirect 70 | ) 71 | 72 | require ( 73 | github.com/DataDog/datadog-lambda-go v1.13.0 74 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect 75 | gopkg.in/DataDog/dd-trace-go.v1 v1.58.0 76 | ) 77 | -------------------------------------------------------------------------------- /examples/lambda/go/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/aws/aws-lambda-go/lambda" 7 | "github.com/DataDog/datadog-lambda-go" 8 | "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" 9 | httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http" 10 | "net/http" 11 | "time" 12 | ) 13 | 14 | type MyEvent struct { 15 | Name string `json:"name"` 16 | } 17 | 18 | func HandleRequest(ctx context.Context, event *MyEvent) (*string, error) { 19 | // Trace an HTTP request 20 | req, _ := http.NewRequestWithContext(ctx, "GET", "https://www.datadoghq.com", nil) 21 | client := http.Client{} 22 | client = *httptrace.WrapClient(&client) 23 | client.Do(req) 24 | 25 | // Submit a custom metric 26 | ddlambda.Metric( 27 | "coffee_house.order_value", // Metric name 28 | 12.45, // Metric value 29 | "product:latte", "order:online", // Associated tags 30 | ) 31 | 32 | // Create a custom span 33 | s, _ := tracer.StartSpanFromContext(ctx, "child.span") 34 | time.Sleep(100 * time.Millisecond) 35 | s.Finish() 36 | 37 | if event == nil { 38 | return nil, fmt.Errorf("received nil event") 39 | } 40 | 41 | message := fmt.Sprintf("Hello %s!", event.Name) 42 | return &message, nil 43 | } 44 | 45 | func main() { 46 | // Wrap your lambda handler 47 | lambda.Start(ddlambda.WrapFunction(HandleRequest, nil)) 48 | } 49 | -------------------------------------------------------------------------------- /examples/lambda/node/hello.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | const { 4 | sendDistributionMetric, 5 | sendDistributionMetricWithDate, 6 | } = require("datadog-lambda-js"); 7 | const tracer = require("dd-trace"); 8 | 9 | // submit a custom span named "sleep" 10 | const sleep = tracer.wrap("sleep", (ms) => { 11 | return new Promise((resolve) => setTimeout(resolve, ms)); 12 | }); 13 | 14 | exports.lambda_handler = async (event) => { 15 | await axios.get("https://www.datadoghq.com"); 16 | 17 | // add custom tags to the lambda function span, 18 | // does NOT work when X-Ray tracing is enabled 19 | const span = tracer.scope().active(); 20 | span.setTag("customer_id", "123456"); 21 | 22 | await sleep(100); 23 | 24 | // submit a custom span 25 | const sandwich = tracer.trace("hello.world", () => { 26 | console.log("Hello, World!"); 27 | }); 28 | 29 | // submit a custom metric 30 | sendDistributionMetric( 31 | "coffee_house.order_value", // metric name 32 | 12.45, // metric value 33 | "product:latte", // tag 34 | "order:online" // another tag 35 | ); 36 | 37 | // submit a custom metric with timestamp 38 | sendDistributionMetricWithDate( 39 | "coffee_house.order_value", // metric name 40 | 12.45, // metric value 41 | new Date(Date.now()), // date, must be within last 20 mins 42 | "product:latte", // tag 43 | "order:online" // another tag 44 | ); 45 | 46 | console.log("Logging from hello.js"); 47 | 48 | const response = { 49 | statusCode: 200, 50 | body: JSON.stringify({ message: "Hello from CDK Node!", another: "field" }), 51 | }; 52 | return response; 53 | }; 54 | -------------------------------------------------------------------------------- /examples/lambda/node/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdk-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "cdk-example", 9 | "version": "1.0.0", 10 | "dependencies": { 11 | "axios": "^1.8.2" 12 | } 13 | }, 14 | "node_modules/asynckit": { 15 | "version": "0.4.0", 16 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 17 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 18 | }, 19 | "node_modules/axios": { 20 | "version": "1.8.2", 21 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz", 22 | "integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==", 23 | "license": "MIT", 24 | "dependencies": { 25 | "follow-redirects": "^1.15.6", 26 | "form-data": "^4.0.0", 27 | "proxy-from-env": "^1.1.0" 28 | } 29 | }, 30 | "node_modules/combined-stream": { 31 | "version": "1.0.8", 32 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 33 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 34 | "dependencies": { 35 | "delayed-stream": "~1.0.0" 36 | }, 37 | "engines": { 38 | "node": ">= 0.8" 39 | } 40 | }, 41 | "node_modules/delayed-stream": { 42 | "version": "1.0.0", 43 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 44 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 45 | "engines": { 46 | "node": ">=0.4.0" 47 | } 48 | }, 49 | "node_modules/follow-redirects": { 50 | "version": "1.15.6", 51 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", 52 | "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", 53 | "funding": [ 54 | { 55 | "type": "individual", 56 | "url": "https://github.com/sponsors/RubenVerborgh" 57 | } 58 | ], 59 | "engines": { 60 | "node": ">=4.0" 61 | }, 62 | "peerDependenciesMeta": { 63 | "debug": { 64 | "optional": true 65 | } 66 | } 67 | }, 68 | "node_modules/form-data": { 69 | "version": "4.0.0", 70 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 71 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 72 | "dependencies": { 73 | "asynckit": "^0.4.0", 74 | "combined-stream": "^1.0.8", 75 | "mime-types": "^2.1.12" 76 | }, 77 | "engines": { 78 | "node": ">= 6" 79 | } 80 | }, 81 | "node_modules/mime-db": { 82 | "version": "1.52.0", 83 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 84 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 85 | "engines": { 86 | "node": ">= 0.6" 87 | } 88 | }, 89 | "node_modules/mime-types": { 90 | "version": "2.1.35", 91 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 92 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 93 | "dependencies": { 94 | "mime-db": "1.52.0" 95 | }, 96 | "engines": { 97 | "node": ">= 0.6" 98 | } 99 | }, 100 | "node_modules/proxy-from-env": { 101 | "version": "1.1.0", 102 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 103 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /examples/lambda/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdk-example", 3 | "version": "1.0.0", 4 | "main": "hello.js", 5 | "dependencies": { 6 | "axios": "^1.8.2" 7 | } 8 | } -------------------------------------------------------------------------------- /examples/lambda/python/hello.py: -------------------------------------------------------------------------------- 1 | import time 2 | import httpx 3 | from ddtrace import tracer 4 | from datadog_lambda.metric import lambda_metric 5 | 6 | 7 | def lambda_handler(event, context): 8 | # add custom tags to the lambda function span, 9 | # does NOT work when X-Ray tracing is enabled 10 | current_span = tracer.current_span() 11 | if current_span: 12 | current_span.set_tag("customer.id", "123456") 13 | 14 | # submit a custom span 15 | with tracer.trace("hello.world"): 16 | print("Hello, World!") 17 | 18 | # submit a custom metric 19 | lambda_metric( 20 | metric_name="coffee_house.order_value", 21 | value=12.45, 22 | timestamp=int(time.time()), # optional, must be within last 20 mins 23 | tags=["product:latte", "order:online"], 24 | ) 25 | 26 | httpx.get("https://www.datadoghq.com") 27 | 28 | return {"statusCode": 200, "body": get_message()} 29 | 30 | 31 | # trace a function 32 | @tracer.wrap() 33 | def get_message(): 34 | return "Hello from CDK!" 35 | -------------------------------------------------------------------------------- /examples/lambda/python/requirements.txt: -------------------------------------------------------------------------------- 1 | httpx==0.23.0 2 | -------------------------------------------------------------------------------- /examples/python-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK Python Example 2 | 3 | Use this example Python stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library. It contains Node, Python, and Go Lambda functions. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 1. Run `export DD_API_KEY=` to set the Datadog API key in your shell session. 9 | 1. Run `virtualenv env` to create a virtual environment. 10 | 1. Run `source env/bin/activate` to activate the virtual environment. 11 | 1. Run `pip install -r requirements.txt` to install dependencies. 12 | 1. Update the layer versions in [cdk_python/cdk_python_stack.py](https://github.com/DataDog/datadog-cdk-constructs/blob/d2f1f60b7e0594ae77dd76a7f5964bee651e8022/examples/python-stack/cdk_python/cdk_python_stack.py#L72-L74) with the latest releases: 13 | - Datadog Lambda Extension: https://github.com/DataDog/datadog-lambda-extension/releases 14 | - Python Layer: https://github.com/DataDog/datadog-lambda-python/releases 15 | - Node Layer: https://github.com/DataDog/datadog-lambda-js/releases 16 | 1. Run `cdk synth` to synthesize the CloudFormation template. 17 | 1. Run `cdk diff` to see the resource and permission changes that are made. 18 | 1. Run `cdk deploy` to deploy the stack to AWS. 19 | 1. Invoke your Lambda functions and look for them in [Datadog Serverless Monitoring](https://app.datadoghq.com/functions?cloud=aws). 20 | 21 | ![Image 2023-11-02 at 11 44 22 AM](https://github.com/DataDog/datadog-cdk-constructs/assets/35278470/9c7b7b15-27ff-4de1-8f54-f5c352f1774b) 22 | -------------------------------------------------------------------------------- /examples/python-stack/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from aws_cdk import App 3 | from cdk_python.cdk_python_stack import CdkPythonStack 4 | 5 | app = App() 6 | CdkPythonStack(app, "CdkPythonStack") 7 | 8 | app.synth() 9 | -------------------------------------------------------------------------------- /examples/python-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "python3 app.py", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "requirements.txt", 11 | "__pycache__" 12 | ] 13 | }, 14 | "context": { 15 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 16 | "@aws-cdk/core:checkSecretUsage": true, 17 | "@aws-cdk/core:target-partitions": [ 18 | "aws", 19 | "aws-cn" 20 | ], 21 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 22 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 23 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 24 | "@aws-cdk/aws-iam:minimizePolicies": true, 25 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 26 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 27 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 28 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 29 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 30 | "@aws-cdk/core:enablePartitionLiterals": true, 31 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 32 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 33 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true 34 | } 35 | } -------------------------------------------------------------------------------- /examples/python-stack/cdk_python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataDog/datadog-cdk-constructs/5ca6da122a1059e215a51151f3efa2789810500b/examples/python-stack/cdk_python/__init__.py -------------------------------------------------------------------------------- /examples/python-stack/cdk_python/cdk_python_stack.py: -------------------------------------------------------------------------------- 1 | from constructs import Construct 2 | from datadog_cdk_constructs_v2 import DatadogLambda, DatadogLambdaProps 3 | import os 4 | from cdk_python.cdk_python_stack_base import CdkPythonStackBase 5 | 6 | class CdkPythonStack(CdkPythonStackBase): 7 | def __init__(self, scope: Construct, id: str, **kwargs) -> None: 8 | super().__init__(scope, id, **kwargs) 9 | 10 | datadog = DatadogLambda( 11 | self, 12 | "Datadog", 13 | dotnet_layer_version=15, 14 | node_layer_version=107, 15 | python_layer_version=89, 16 | extension_layer_version=55, 17 | add_layers=True, 18 | api_key=os.getenv("DD_API_KEY"), 19 | enable_datadog_tracing=True, 20 | enable_datadog_asm=True, 21 | flush_metrics_to_logs=True, 22 | site="datadoghq.com", 23 | ) 24 | 25 | # Ensure DatadogLambdaProps can be imported properly 26 | props = DatadogLambdaProps() 27 | datadog.add_lambda_functions(self.lambdaFunctions) 28 | -------------------------------------------------------------------------------- /examples/python-stack/cdk_python/cdk_python_stack_base.py: -------------------------------------------------------------------------------- 1 | from aws_cdk import ( 2 | aws_lambda as _lambda, 3 | aws_lambda_go_alpha as go, 4 | BundlingOptions, 5 | BundlingOutput, 6 | Duration, 7 | Stack, 8 | ) 9 | from constructs import Construct 10 | 11 | 12 | class CdkPythonStackBase(Stack): 13 | def __init__(self, scope: Construct, id: str, **kwargs) -> None: 14 | super().__init__(scope, id, **kwargs) 15 | 16 | print("Creating Hello World Python stack") 17 | 18 | hello_node = _lambda.Function( 19 | self, 20 | "hello-node", 21 | runtime=_lambda.Runtime.NODEJS_20_X, 22 | timeout=Duration.seconds(10), 23 | memory_size=256, 24 | code=_lambda.Code.from_asset( 25 | "../lambda/node", 26 | bundling=BundlingOptions( 27 | image=_lambda.Runtime.NODEJS_20_X.bundling_image, 28 | command=[ 29 | "bash", 30 | "-c", 31 | "cp -aT . /asset-output && npm install --prefix /asset-output", 32 | ], 33 | user="root", 34 | ), 35 | ), 36 | handler="hello.lambda_handler", 37 | ) 38 | 39 | hello_python = _lambda.Function( 40 | self, 41 | "hello-python", 42 | runtime=_lambda.Runtime.PYTHON_3_11, 43 | timeout=Duration.seconds(10), 44 | memory_size=256, 45 | code=_lambda.Code.from_asset( 46 | "../lambda/python", 47 | bundling=BundlingOptions( 48 | image=_lambda.Runtime.PYTHON_3_11.bundling_image, 49 | command=[ 50 | "bash", 51 | "-c", 52 | "pip install -r requirements.txt -t /asset-output && cp -aT . /asset-output", 53 | ], 54 | ), 55 | ), 56 | handler="hello.lambda_handler", 57 | ) 58 | 59 | hello_go = go.GoFunction( 60 | self, 61 | "hello-go", 62 | entry="../lambda/go/hello.go", 63 | runtime=_lambda.Runtime.PROVIDED_AL2, 64 | timeout=Duration.seconds(10), 65 | bundling=go.BundlingOptions( 66 | go_build_flags=['-ldflags "-s -w"'], 67 | ), 68 | ) 69 | 70 | hello_dotnet = _lambda.Function( 71 | self, 72 | "hello-dotnet", 73 | runtime=_lambda.Runtime.DOTNET_8, 74 | handler="HelloWorld::HelloWorld.Handler::SayHi", 75 | timeout=Duration.seconds(10), 76 | memory_size=256, 77 | code=_lambda.Code.from_asset( 78 | "../lambda/dotnet", 79 | bundling=BundlingOptions( 80 | image=_lambda.Runtime.DOTNET_8.bundling_image, 81 | command=[ 82 | '/bin/sh', 83 | '-c', 84 | ' dotnet tool install -g Amazon.Lambda.Tools' + 85 | ' && dotnet build' + 86 | ' && dotnet lambda package --output-package /asset-output/function.zip' 87 | ], 88 | user="root", 89 | output_type=BundlingOutput.ARCHIVED 90 | ), 91 | ), 92 | ) 93 | 94 | self.lambdaFunctions = [hello_node, hello_python, hello_go, hello_dotnet] 95 | -------------------------------------------------------------------------------- /examples/python-stack/requirements.txt: -------------------------------------------------------------------------------- 1 | aws-cdk-lib~=2.177.0 2 | aws-cdk.aws-lambda-go-alpha~=2.134.0a0 3 | constructs~=10.0.5 4 | datadog_cdk_constructs_v2~=2.0.0 5 | -------------------------------------------------------------------------------- /examples/step-functions-go-stack/.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | app 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # go.sum should be committed 16 | !go.sum 17 | 18 | # CDK asset staging directory 19 | .cdk.staging 20 | cdk.out 21 | 22 | # The copied Go package for dev testing 23 | ddcdkconstruct/ 24 | -------------------------------------------------------------------------------- /examples/step-functions-go-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK Go Example 2 | 3 | Use this example Go stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library for Step Functions. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 1. Run `export DD_API_KEY=` to set the Datadog API key in your shell session. 9 | 1. Set up Datadog forwarder ([Datadog Forwarder documentation](https://docs.datadoghq.com/logs/guide/forwarder/?tab=cloudformation#installation)). 10 | 1. Run `export DD_FORWARDER_ARN=` to set the Datadog forwarder ARN in your shell session. 11 | 1. Run `cdk synth` to synthesize the CloudFormation template. 12 | 1. Run `cdk diff` to see the resource and permission changes that are made. 13 | 1. Run `cdk deploy` to deploy the stack to AWS. 14 | 1. Invoke your Lambda functions and look for them in [Datadog Serverless Monitoring](https://app.datadoghq.com/functions?cloud=aws). 15 | 16 | ![Datadog CDK Go Stack](https://github.com/user-attachments/assets/ba9ceae7-df3a-4d4b-8c51-6a29d82d25b1) 17 | 18 | ## Resources 19 | 20 | This demo project was created and modified from [Tutorial: Create your first AWS CDK app](https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html) 21 | -------------------------------------------------------------------------------- /examples/step-functions-go-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "go mod download && go run app.go", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "go.mod", 11 | "go.sum", 12 | "**/*test.go" 13 | ] 14 | }, 15 | "context": { 16 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 17 | "@aws-cdk/core:checkSecretUsage": true, 18 | "@aws-cdk/core:target-partitions": [ 19 | "aws", 20 | "aws-cn" 21 | ], 22 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 23 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 24 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 25 | "@aws-cdk/aws-iam:minimizePolicies": true, 26 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 27 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 28 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 29 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 30 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 31 | "@aws-cdk/core:enablePartitionLiterals": true, 32 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 33 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 34 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 35 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 36 | "@aws-cdk/aws-route53-patters:useCertificate": true, 37 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 38 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 39 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 40 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 41 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 42 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 43 | "@aws-cdk/aws-redshift:columnId": true, 44 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 45 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 46 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 47 | "@aws-cdk/aws-kms:aliasNameRef": true, 48 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 49 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 50 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 51 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 52 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 53 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 54 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 55 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 56 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, 57 | "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, 58 | "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, 59 | "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, 60 | "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, 61 | "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, 62 | "@aws-cdk/aws-eks:nodegroupNameAttribute": true, 63 | "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, 64 | "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, 65 | "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, 66 | "@aws-cdk/aws-stepfunctions-tasks:ecsReduceRunTaskPermissions": true 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/step-functions-go-stack/go.mod: -------------------------------------------------------------------------------- 1 | module app 2 | 3 | go 1.22.0 4 | 5 | toolchain go1.22.5 6 | 7 | require ( 8 | github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2 v2.0.0 9 | github.com/aws/aws-cdk-go/awscdk/v2 v2.167.0 10 | github.com/aws/constructs-go/constructs/v10 v10.4.2 11 | github.com/aws/jsii-runtime-go v1.106.0 12 | ) 13 | 14 | require ( 15 | github.com/Masterminds/semver/v3 v3.3.1 // indirect 16 | github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.220 // indirect 17 | github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.3 // indirect 18 | github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv6/v2 v2.1.0 // indirect 19 | github.com/cdklabs/cloud-assembly-schema-go/awscdkcloudassemblyschema/v38 v38.0.1 // indirect 20 | github.com/fatih/color v1.18.0 // indirect 21 | github.com/mattn/go-colorable v0.1.13 // indirect 22 | github.com/mattn/go-isatty v0.0.20 // indirect 23 | github.com/yuin/goldmark v1.4.13 // indirect 24 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 25 | golang.org/x/mod v0.22.0 // indirect 26 | golang.org/x/sync v0.10.0 // indirect 27 | golang.org/x/sys v0.28.0 // indirect 28 | golang.org/x/tools v0.28.0 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /examples/step-functions-python-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK Python Example 2 | 3 | Use this example Python stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library for Step Functions. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 2. Run `export DD_API_KEY=` to set the Datadog API key in your shell session. 9 | 3. Set up Datadog forwarder ([Datadog Forwarder documentation](https://docs.datadoghq.com/logs/guide/forwarder/?tab=cloudformation#installation)). 10 | 4. Run `export DD_FORWARDER_ARN=` to set the Datadog forwarder ARN in your shell session. 11 | 5. Run `virtualenv env` to create a virtual environment. 12 | 6. Run `source env/bin/activate` to activate the virtual environment. 13 | 7. Run `pip install -r requirements.txt` to install dependencies. 14 | 8. Run `cdk synth` to synthesize the CloudFormation template. 15 | 9. Run `cdk diff` to see the resource and permission changes that are made. 16 | 10. Run `cdk deploy` to deploy the stack to AWS. 17 | 11. Invoke your Step Function and look for them in [Datadog Serverless Monitoring](https://app.datadoghq.com/functions?cloud=aws&entity_view=step_functions). 18 | 19 | ![Datadog CDK Python Stack](https://github.com/user-attachments/assets/fad74221-237a-4641-b27b-24f9e7d059ed) 20 | -------------------------------------------------------------------------------- /examples/step-functions-python-stack/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from aws_cdk import App 3 | from cdk_step_functions_python_stack import CdkStepFunctionsPythonStack 4 | 5 | app = App() 6 | CdkStepFunctionsPythonStack(app, "CdkStepFunctionsPythonStack") 7 | 8 | app.synth() 9 | -------------------------------------------------------------------------------- /examples/step-functions-python-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "python3 app.py", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "requirements.txt", 11 | "__pycache__" 12 | ] 13 | }, 14 | "context": { 15 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 16 | "@aws-cdk/core:checkSecretUsage": true, 17 | "@aws-cdk/core:target-partitions": [ 18 | "aws", 19 | "aws-cn" 20 | ], 21 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 22 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 23 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 24 | "@aws-cdk/aws-iam:minimizePolicies": true, 25 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 26 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 27 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 28 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 29 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 30 | "@aws-cdk/core:enablePartitionLiterals": true, 31 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 32 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 33 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true 34 | } 35 | } -------------------------------------------------------------------------------- /examples/step-functions-python-stack/cdk_step_functions_python_stack.py: -------------------------------------------------------------------------------- 1 | from aws_cdk import ( 2 | Duration, 3 | Stack, 4 | BundlingOptions, 5 | aws_lambda as _lambda, 6 | aws_stepfunctions as sfn, 7 | aws_stepfunctions_tasks as tasks, 8 | ) 9 | import os 10 | from constructs import Construct 11 | from datadog_cdk_constructs_v2 import DatadogStepFunctions, DatadogLambda 12 | 13 | 14 | class CdkStepFunctionsPythonStack(Stack): 15 | def __init__(self, scope: Construct, id: str, **kwargs) -> None: 16 | super().__init__(scope, id, **kwargs) 17 | 18 | print("Setting up the child state machine") 19 | 20 | pass_state = sfn.Pass(self, "PassState") 21 | wait_state = sfn.Wait( 22 | self, "WaitState", time=sfn.WaitTime.duration(Duration.seconds(1)) 23 | ) 24 | success_state = sfn.Succeed(self, "SuccessState") 25 | 26 | child_state_machine = sfn.StateMachine( 27 | self, 28 | "CdkPythonTestChildStateMachine", 29 | definition_body=sfn.DefinitionBody.from_chainable( 30 | pass_state.next(wait_state).next(success_state) 31 | ), 32 | ) 33 | 34 | print("Setting up the parent state machine") 35 | 36 | invoke_child_state_machine_task = tasks.StepFunctionsStartExecution( 37 | self, 38 | "InvokeChildStateMachineTask", 39 | state_machine=child_state_machine, 40 | input=sfn.TaskInput.from_object( 41 | DatadogStepFunctions.build_step_function_task_input_to_merge_traces( 42 | {"custom-key": "custom-value"} 43 | ) 44 | ), 45 | ) 46 | 47 | hello_lambda_function = _lambda.Function( 48 | self, 49 | "hello-python", 50 | runtime=_lambda.Runtime.PYTHON_3_12, 51 | timeout=Duration.seconds(10), 52 | memory_size=256, 53 | code=_lambda.Code.from_asset( 54 | "../lambda/python", 55 | bundling=BundlingOptions( 56 | image=_lambda.Runtime.PYTHON_3_12.bundling_image, 57 | command=[ 58 | "bash", 59 | "-c", 60 | "pip install -r requirements.txt -t /asset-output && cp -aT . /asset-output", 61 | ], 62 | ), 63 | ), 64 | handler="hello.lambda_handler", 65 | ) 66 | 67 | lambda_task = tasks.LambdaInvoke( 68 | self, 69 | "MyLambdaTask", 70 | lambda_function=hello_lambda_function, 71 | payload=sfn.TaskInput.from_object( 72 | DatadogStepFunctions.build_lambda_payload_to_merge_traces() 73 | ), 74 | ) 75 | 76 | parent_state_machine = sfn.StateMachine( 77 | self, 78 | "CdkPythonTestStateMachine", 79 | definition_body=sfn.DefinitionBody.from_chainable( 80 | lambda_task.next(invoke_child_state_machine_task) 81 | ), 82 | ) 83 | 84 | # Instrument the lambda functions and the state machines 85 | print("Instrumenting Step Functions in Python stack with Datadog") 86 | 87 | datadog_sfn = DatadogStepFunctions( 88 | self, 89 | "DatadogSfn", 90 | env="dev", 91 | service="cdk-test-service", 92 | version="1.0.0", 93 | forwarder_arn=os.getenv("DD_FORWARDER_ARN"), 94 | tags="custom-tag-1:tag-value-1,custom-tag-2:tag-value-2", 95 | ) 96 | datadog_sfn.add_state_machines([child_state_machine, parent_state_machine]) 97 | 98 | datadog_lambda = DatadogLambda( 99 | self, 100 | "DatadogLambda", 101 | python_layer_version=101, 102 | extension_layer_version=65, 103 | add_layers=True, 104 | api_key=os.getenv("DD_API_KEY"), 105 | enable_datadog_tracing=True, 106 | enable_datadog_asm=True, 107 | flush_metrics_to_logs=True, 108 | site="datadoghq.com", 109 | env="dev", 110 | service="cdk-test-service", 111 | version="1.0.0", 112 | ) 113 | datadog_lambda.add_lambda_functions([hello_lambda_function]) 114 | -------------------------------------------------------------------------------- /examples/step-functions-python-stack/datadog-cdk-constructs-v2-1.18.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DataDog/datadog-cdk-constructs/5ca6da122a1059e215a51151f3efa2789810500b/examples/step-functions-python-stack/datadog-cdk-constructs-v2-1.18.0.tar.gz -------------------------------------------------------------------------------- /examples/step-functions-python-stack/requirements.txt: -------------------------------------------------------------------------------- 1 | aws-cdk-lib~=2.177.0 2 | aws-cdk.aws-lambda-go-alpha~=2.134.0a0 3 | constructs~=10.0.5 4 | datadog_cdk_constructs_v2~=1.18.0 5 | -------------------------------------------------------------------------------- /examples/step-functions-typescript-stack/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /examples/step-functions-typescript-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK TypeScript Example 2 | 3 | Use this example TypeScript stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library for Step Functions. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 1. Run `export DD_API_KEY=` to set the Datadog API key in your shell session. 9 | 1. Set up Datadog forwarder ([Datadog Forwarder documentation](https://docs.datadoghq.com/logs/guide/forwarder/?tab=cloudformation#installation)). 10 | 1. Run `export DD_FORWARDER_ARN=` to set the Datadog forwarder ARN in your shell session. 11 | 1. Run `yarn` install dependencies. 12 | 1. Run `cdk synth` to synthesize the CloudFormation template. 13 | 1. Run `cdk diff` to see the resource and permission changes that are made. 14 | 1. Run `cdk deploy --all` to deploy the stacks to AWS. 15 | 1. Invoke your Step Function and look for them in [Datadog Serverless Monitoring](https://app.datadoghq.com/functions?cloud=aws&entity_view=step_functions). 16 | 17 | ![Datadog CDK TypeScript Stack](https://github.com/user-attachments/assets/202ed91a-f034-42e9-83c8-12e82fa101e2) 18 | -------------------------------------------------------------------------------- /examples/step-functions-typescript-stack/bin/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as cdk from "aws-cdk-lib"; 3 | import { CdkStepFunctionsTypeScriptStack } from "../lib/cdk-step-functions-typescript-stack"; 4 | 5 | const app = new cdk.App(); 6 | // Ensure there's no identifier collision when a stack has multiple instances in the app 7 | new CdkStepFunctionsTypeScriptStack(app, "CdkStepFunctionsTypeScriptStack1", {}); 8 | new CdkStepFunctionsTypeScriptStack(app, "CdkStepFunctionsTypeScriptStack2", {}); 9 | app.synth(); 10 | -------------------------------------------------------------------------------- /examples/step-functions-typescript-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/index.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules" 16 | ] 17 | }, 18 | "context": { 19 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 20 | "@aws-cdk/core:checkSecretUsage": true, 21 | "@aws-cdk/core:target-partitions": [ 22 | "aws", 23 | "aws-cn" 24 | ], 25 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 26 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 27 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 28 | "@aws-cdk/aws-iam:minimizePolicies": true, 29 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 30 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 31 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 32 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 33 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 34 | "@aws-cdk/core:enablePartitionLiterals": true, 35 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 36 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 37 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/step-functions-typescript-stack/lib/cdk-step-functions-typescript-stack.ts: -------------------------------------------------------------------------------- 1 | import * as lambda from "aws-cdk-lib/aws-lambda"; 2 | import * as sfn from "aws-cdk-lib/aws-stepfunctions"; 3 | import { Duration, Stack, StackProps } from "aws-cdk-lib"; 4 | import { Construct } from "constructs"; 5 | import { DatadogStepFunctions, DatadogLambda } from "datadog-cdk-constructs-v2"; 6 | import * as tasks from "aws-cdk-lib/aws-stepfunctions-tasks"; 7 | 8 | export class CdkStepFunctionsTypeScriptStack extends Stack { 9 | constructor(scope: Construct, id: string, props?: StackProps) { 10 | super(scope, id, props); 11 | 12 | console.log("Creating Hello World TypeScript stack"); 13 | 14 | /* Set up the child state machine */ 15 | 16 | const passState = new sfn.Pass(this, "PassState"); 17 | const waitState = new sfn.Wait(this, "WaitState", { time: sfn.WaitTime.duration(Duration.seconds(1)) }); 18 | const successState = new sfn.Succeed(this, "SuccessState"); 19 | 20 | const childStateMachine = new sfn.StateMachine(this, "CdkTypeScriptTestChildStateMachine", { 21 | definitionBody: sfn.DefinitionBody.fromChainable(passState.next(waitState).next(successState)), 22 | }); 23 | 24 | /* Set up the parent state machine */ 25 | 26 | const invokeChildStateMachineTask = new tasks.StepFunctionsStartExecution(this, "InvokeChildStateMachineTask", { 27 | stateMachine: childStateMachine, 28 | input: sfn.TaskInput.fromObject( 29 | DatadogStepFunctions.buildStepFunctionTaskInputToMergeTraces({ "custom-key": "custom-value" }), 30 | ), 31 | }); 32 | 33 | const helloLambdaFunction = new lambda.Function(this, "hello-python", { 34 | runtime: lambda.Runtime.PYTHON_3_12, 35 | timeout: Duration.seconds(10), 36 | memorySize: 256, 37 | code: lambda.Code.fromAsset("../lambda/python", { 38 | bundling: { 39 | image: lambda.Runtime.PYTHON_3_12.bundlingImage, 40 | command: ["bash", "-c", "pip install -r requirements.txt -t /asset-output && cp -aT . /asset-output"], 41 | }, 42 | }), 43 | handler: "hello.lambda_handler", 44 | }); 45 | 46 | const lambdaTask = new tasks.LambdaInvoke(this, "MyLambdaTask", { 47 | lambdaFunction: helloLambdaFunction, 48 | payload: sfn.TaskInput.fromObject(DatadogStepFunctions.buildLambdaPayloadToMergeTraces()), 49 | }); 50 | 51 | const parentStateMachine = new sfn.StateMachine(this, "CdkTypeScriptTestStateMachine", { 52 | definitionBody: sfn.DefinitionBody.fromChainable(lambdaTask.next(invokeChildStateMachineTask)), 53 | }); 54 | 55 | /* Instrument the lambda functions and the state machines */ 56 | 57 | console.log("Instrumenting Step Functions in TypeScript stack with Datadog"); 58 | 59 | const datadogSfn = new DatadogStepFunctions(this, "DatadogSfn", { 60 | env: "dev", 61 | service: "cdk-test-service", 62 | version: "1.0.0", 63 | forwarderArn: process.env.DD_FORWARDER_ARN, 64 | tags: "custom-tag-1:tag-value-1,custom-tag-2:tag-value-2", 65 | }); 66 | datadogSfn.addStateMachines([childStateMachine, parentStateMachine]); 67 | 68 | const datadogLambda = new DatadogLambda(this, "DatadogLambda", { 69 | pythonLayerVersion: 101, 70 | extensionLayerVersion: 65, 71 | addLayers: true, 72 | apiKey: process.env.DD_API_KEY, 73 | enableDatadogTracing: true, 74 | enableDatadogASM: true, 75 | flushMetricsToLogs: true, 76 | site: "datadoghq.com", 77 | env: "dev", 78 | service: "cdk-test-service", 79 | version: "1.0.0", 80 | }); 81 | datadogLambda.addLambdaFunctions([helloLambdaFunction]); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /examples/step-functions-typescript-stack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-stack", 3 | "version": "1.0.0", 4 | "bin": { 5 | "cdk-typescript": "bin/index.js" 6 | }, 7 | "devDependencies": { 8 | "@types/node": "^20.8.8", 9 | "aws-cdk": "^2.134.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "~5.2.2" 12 | }, 13 | "dependencies": { 14 | "@aws-cdk/aws-lambda-go-alpha": "^2.134.0-alpha.0", 15 | "@aws-cdk/aws-lambda-python-alpha": "^2.134.0-alpha.0", 16 | "aws-cdk-lib": "^2.187.0", 17 | "constructs": "^10.3.0", 18 | "datadog-cdk-constructs-v2": "^2.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/typescript-stack/.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /examples/typescript-stack/README.md: -------------------------------------------------------------------------------- 1 | # Datadog CDK TypeScript Example 2 | 3 | Use this example TypeScript stack to try out the [datadog-cdk-constructs](https://github.com/DataDog/datadog-cdk-constructs) v2 library. It contains Node, Python, and Go Lambda functions. 4 | 5 | ## Getting Started 6 | 7 | 1. Get a Datadog API key to send monitoring data ([Datadog API keys documentation](https://docs.datadoghq.com/account_management/api-app-keys/#add-an-api-key-or-client-token)). 8 | 1. Run `export DD_API_KEY=` to set the Datadog API key in your shell session. 9 | 1. Run `yarn` install dependencies. 10 | 1. Update the layer versions in [lib/cdk-typescript-stack.ts](https://github.com/DataDog/datadog-cdk-constructs/blob/d2f1f60b7e0594ae77dd76a7f5964bee651e8022/examples/typescript-stack/lib/cdk-typescript-stack.ts#L66-L68) with the latest releases: 11 | - Datadog Lambda Extension: https://github.com/DataDog/datadog-lambda-extension/releases 12 | - Python Layer: https://github.com/DataDog/datadog-lambda-python/releases 13 | - Node Layer: https://github.com/DataDog/datadog-lambda-js/releases 14 | 1. Run `cdk synth` to synthesize the CloudFormation template. 15 | 1. Run `cdk diff` to see the resource and permission changes that are made. 16 | 1. Run `cdk deploy` to deploy the stack to AWS. 17 | 1. Invoke your Lambda functions and look for them in [Datadog Serverless Monitoring](https://app.datadoghq.com/functions?cloud=aws). 18 | 19 | ![Image 2023-11-02 at 11 46 56 AM](https://github.com/DataDog/datadog-cdk-constructs/assets/35278470/bfea4180-e7d9-4408-b43d-e60a2bf01c04) 20 | -------------------------------------------------------------------------------- /examples/typescript-stack/bin/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as cdk from "aws-cdk-lib"; 3 | import { CdkTypeScriptStack } from "../lib/cdk-typescript-stack"; 4 | 5 | const app = new cdk.App(); 6 | new CdkTypeScriptStack(app, "CdkTypeScriptStack", {}); 7 | app.synth(); 8 | -------------------------------------------------------------------------------- /examples/typescript-stack/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/index.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules" 16 | ] 17 | }, 18 | "context": { 19 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 20 | "@aws-cdk/core:checkSecretUsage": true, 21 | "@aws-cdk/core:target-partitions": [ 22 | "aws", 23 | "aws-cn" 24 | ], 25 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 26 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 27 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 28 | "@aws-cdk/aws-iam:minimizePolicies": true, 29 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 30 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 31 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 32 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 33 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 34 | "@aws-cdk/core:enablePartitionLiterals": true, 35 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 36 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 37 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/typescript-stack/lib/cdk-typescript-stack-base.ts: -------------------------------------------------------------------------------- 1 | import { GoFunction } from "@aws-cdk/aws-lambda-go-alpha"; 2 | import * as lambda from "aws-cdk-lib/aws-lambda"; 3 | import * as apigwv2 from "aws-cdk-lib/aws-apigatewayv2"; 4 | import { BundlingOutput, Duration, Stack, StackProps } from "aws-cdk-lib"; 5 | import { Function } from "aws-cdk-lib/aws-lambda"; 6 | import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations"; 7 | import { Construct } from "constructs"; 8 | 9 | export abstract class CdkTypeScriptStackBase extends Stack { 10 | protected lambdaFunctions: lambda.Function[]; 11 | constructor(scope: Construct, id: string, props?: StackProps) { 12 | super(scope, id, props); 13 | 14 | console.log("Creating Hello World TypeScript stack"); 15 | 16 | const helloNode = new Function(this, "hello-node", { 17 | runtime: lambda.Runtime.NODEJS_20_X, 18 | memorySize: 256, 19 | timeout: Duration.seconds(10), 20 | code: lambda.Code.fromAsset("../lambda/node", { 21 | bundling: { 22 | image: lambda.Runtime.NODEJS_20_X.bundlingImage, 23 | command: ["bash", "-c", "cp -aT . /asset-output && npm install --prefix /asset-output"], 24 | user: "root", 25 | }, 26 | }), 27 | handler: "hello.lambda_handler", 28 | }); 29 | 30 | const helloPython = new Function(this, "hello-python", { 31 | runtime: lambda.Runtime.PYTHON_3_12, 32 | timeout: Duration.seconds(10), 33 | memorySize: 256, 34 | code: lambda.Code.fromAsset("../lambda/python", { 35 | bundling: { 36 | image: lambda.Runtime.PYTHON_3_12.bundlingImage, 37 | command: ["bash", "-c", "pip install -r requirements.txt -t /asset-output && cp -aT . /asset-output"], 38 | }, 39 | }), 40 | handler: "hello.lambda_handler", 41 | }); 42 | 43 | const helloGo = new GoFunction(this, "hello-go", { 44 | entry: "../lambda/go/hello.go", 45 | architecture: lambda.Architecture.ARM_64, 46 | runtime: lambda.Runtime.PROVIDED_AL2, 47 | timeout: Duration.seconds(10), 48 | bundling: { 49 | goBuildFlags: ['-ldflags "-s -w"'], 50 | }, 51 | environment: { 52 | LOG_LEVEL: "INFO", 53 | TABLE_NAME: "HelloWorld", 54 | }, 55 | }); 56 | 57 | const helloDotnet = new Function(this, "hello-dotnet", { 58 | runtime: lambda.Runtime.DOTNET_8, 59 | handler: "HelloWorld::HelloWorld.Handler::SayHi", 60 | memorySize: 256, 61 | code: lambda.Code.fromAsset("../lambda/dotnet/", { 62 | bundling: { 63 | image: lambda.Runtime.DOTNET_8.bundlingImage, 64 | command: [ 65 | "/bin/sh", 66 | "-c", 67 | " dotnet tool install -g Amazon.Lambda.Tools" + 68 | " && dotnet build" + 69 | " && dotnet lambda package --output-package /asset-output/function.zip", 70 | ], 71 | user: "root", 72 | outputType: BundlingOutput.ARCHIVED, 73 | }, 74 | }), 75 | }); 76 | 77 | this.lambdaFunctions = [helloNode, helloPython, helloGo, helloDotnet]; 78 | 79 | const dotnetHttpIntegration = new HttpLambdaIntegration("GetDotnetIntegration", helloDotnet); 80 | const dotnetHttpApi = new apigwv2.HttpApi(this, "dotnetHttpApi"); 81 | dotnetHttpApi.addRoutes({ 82 | path: "/hello", 83 | methods: [apigwv2.HttpMethod.GET], 84 | integration: dotnetHttpIntegration, 85 | }); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /examples/typescript-stack/lib/cdk-typescript-stack.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { DatadogLambda, DatadogLambdaProps } from "datadog-cdk-constructs-v2"; 4 | import { CdkTypeScriptStackBase } from "./cdk-typescript-stack-base"; 5 | 6 | export class CdkTypeScriptStack extends CdkTypeScriptStackBase { 7 | constructor(scope: Construct, id: string, props?: StackProps) { 8 | super(scope, id, props); 9 | 10 | console.log("Instrumenting Lambda Functions in TypeScript stack with Datadog"); 11 | 12 | const datadogLambdaProps: DatadogLambdaProps = { 13 | dotnetLayerVersion: 15, 14 | nodeLayerVersion: 108, 15 | pythonLayerVersion: 89, 16 | extensionLayerVersion: 55, 17 | addLayers: true, 18 | apiKey: process.env.DD_API_KEY, 19 | enableDatadogTracing: true, 20 | enableDatadogASM: true, 21 | flushMetricsToLogs: true, 22 | site: "datadoghq.com", 23 | }; 24 | 25 | const datadog = new DatadogLambda(this, "Datadog", datadogLambdaProps); 26 | 27 | datadog.addLambdaFunctions(this.lambdaFunctions); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/typescript-stack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-stack", 3 | "version": "1.0.0", 4 | "bin": { 5 | "cdk-typescript": "bin/index.js" 6 | }, 7 | "devDependencies": { 8 | "@types/node": "^20.8.8", 9 | "aws-cdk": "^2.134.0", 10 | "ts-node": "^10.9.1", 11 | "typescript": "~5.2.2" 12 | }, 13 | "dependencies": { 14 | "@aws-cdk/aws-lambda-go-alpha": "^2.134.0-alpha.0", 15 | "@aws-cdk/aws-lambda-python-alpha": "^2.134.0-alpha.0", 16 | "aws-cdk-lib": "^2.187.0", 17 | "constructs": "^10.3.0", 18 | "datadog-cdk-constructs-v2": "^2.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/typescript-stack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020", 7 | "dom" 8 | ], 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "alwaysStrict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": false, 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "experimentalDecorators": true, 22 | "strictPropertyInitialization": false, 23 | "typeRoots": [ 24 | "./node_modules/@types" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "cdk.out" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /integration_tests/lambda/example-java.java: -------------------------------------------------------------------------------- 1 | import java.util.Map; 2 | import com.amazonaws.services.lambda.runtime.Context; 3 | import com.amazonaws.services.lambda.runtime.RequestHandler; 4 | 5 | public class HelloLambda implements RequestHandler, String> { 6 | @Override 7 | public String handleRequest(final Map event, final Context context) { 8 | return null; 9 | } 10 | } -------------------------------------------------------------------------------- /integration_tests/lambda/example-lambda.ts: -------------------------------------------------------------------------------- 1 | export const handler = (): void => { 2 | return; 3 | }; 4 | -------------------------------------------------------------------------------- /integration_tests/lambda/example-python.py: -------------------------------------------------------------------------------- 1 | def handler(event, context): 2 | return {} 3 | -------------------------------------------------------------------------------- /integration_tests/snapshots/.gitignore: -------------------------------------------------------------------------------- 1 | test-*-snapshot.json -------------------------------------------------------------------------------- /integration_tests/stacks/go/.gitignore: -------------------------------------------------------------------------------- 1 | ddcdkconstruct 2 | -------------------------------------------------------------------------------- /integration_tests/stacks/go/go.mod: -------------------------------------------------------------------------------- 1 | module app 2 | 3 | go 1.22.0 4 | 5 | toolchain go1.22.5 6 | 7 | require ( 8 | github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2 v2.0.0 9 | github.com/aws/aws-cdk-go/awscdk/v2 v2.151.0 10 | github.com/aws/constructs-go/constructs/v10 v10.3.0 11 | github.com/aws/jsii-runtime-go v1.106.0 12 | ) 13 | 14 | require ( 15 | github.com/Masterminds/semver/v3 v3.3.1 // indirect 16 | github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.220 // indirect 17 | github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.3 // indirect 18 | github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv6/v2 v2.1.0 // indirect 19 | github.com/fatih/color v1.18.0 // indirect 20 | github.com/mattn/go-colorable v0.1.13 // indirect 21 | github.com/mattn/go-isatty v0.0.20 // indirect 22 | github.com/yuin/goldmark v1.4.13 // indirect 23 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 24 | golang.org/x/mod v0.22.0 // indirect 25 | golang.org/x/sync v0.10.0 // indirect 26 | golang.org/x/sys v0.28.0 // indirect 27 | golang.org/x/tools v0.28.0 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /integration_tests/stacks/go/helpers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/aws/aws-cdk-go/awscdk/v2" 5 | "github.com/aws/aws-cdk-go/awscdk/v2/awslambda" 6 | "github.com/aws/constructs-go/constructs/v10" 7 | "github.com/aws/jsii-runtime-go" 8 | ) 9 | 10 | type AppStackProps struct { 11 | awscdk.StackProps 12 | } 13 | 14 | // Creates a stack without Datadog integration 15 | func NewAppStackWithoutDatadog(scope constructs.Construct, id *string, props *AppStackProps) (awscdk.Stack, awslambda.Function) { 16 | var sprops awscdk.StackProps 17 | if props != nil { 18 | sprops = props.StackProps 19 | } 20 | stack := awscdk.NewStack(scope, id, &sprops) 21 | 22 | myFunction := awslambda.NewFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.FunctionProps{ 23 | Runtime: awslambda.Runtime_NODEJS_20_X(), 24 | Handler: jsii.String("index.handler"), 25 | Code: awslambda.Code_FromInline(jsii.String(` 26 | exports.handler = async function(event) { 27 | return { 28 | statusCode: 200, 29 | body: JSON.stringify('Hello World!'), 30 | }; 31 | }; 32 | `)), 33 | }) 34 | 35 | myFunctionUrl := myFunction.AddFunctionUrl(&awslambda.FunctionUrlOptions{ 36 | AuthType: awslambda.FunctionUrlAuthType_NONE, 37 | }) 38 | 39 | awscdk.NewCfnOutput(stack, jsii.String("myFunctionUrlOutput"), &awscdk.CfnOutputProps{ 40 | Value: myFunctionUrl.Url(), 41 | }) 42 | 43 | return stack, myFunction 44 | } -------------------------------------------------------------------------------- /integration_tests/stacks/go/lambda_go_stack.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/DataDog/datadog-cdk-constructs-go/ddcdkconstruct/v2" 5 | "github.com/aws/aws-cdk-go/awscdk/v2" 6 | "github.com/aws/constructs-go/constructs/v10" 7 | "github.com/aws/jsii-runtime-go" 8 | ) 9 | 10 | // Creates a stack with Datadog integration using the new API (DatadogLambda, DatadogLambdaProps) 11 | func NewAppStackWithDatadogLambda(scope constructs.Construct, id string, props *AppStackProps) awscdk.Stack { 12 | stack, lambdaFunction := NewAppStackWithoutDatadog(scope, &id, props) 13 | 14 | // Set up Datadog integration 15 | datadog := ddcdkconstruct.NewDatadogLambda( 16 | stack, 17 | jsii.String("Datadog"), 18 | &ddcdkconstruct.DatadogLambdaProps{ 19 | NodeLayerVersion: jsii.Number(113), 20 | PythonLayerVersion: jsii.Number(97), 21 | JavaLayerVersion: jsii.Number(21), 22 | DotnetLayerVersion: jsii.Number(15), 23 | AddLayers: jsii.Bool(true), 24 | ExtensionLayerVersion: jsii.Number(62), 25 | FlushMetricsToLogs: jsii.Bool(true), 26 | Site: jsii.String("datadoghq.com"), 27 | ApiKey: jsii.String("1234"), 28 | EnableDatadogTracing: jsii.Bool(true), 29 | EnableMergeXrayTraces: jsii.Bool(true), 30 | EnableDatadogLogs: jsii.Bool(true), 31 | InjectLogContext: jsii.Bool(true), 32 | LogLevel: jsii.String("debug"), 33 | }) 34 | 35 | datadog.AddLambdaFunctions(&[]interface{}{lambdaFunction}, nil) 36 | return stack 37 | } 38 | 39 | -------------------------------------------------------------------------------- /integration_tests/stacks/go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/aws/aws-cdk-go/awscdk/v2" 5 | "github.com/aws/jsii-runtime-go" 6 | ) 7 | 8 | func main() { 9 | defer jsii.Close() 10 | 11 | app := awscdk.NewApp(nil) 12 | 13 | // Creates a stack using the current API (DatadogLambda, DatadogLambdaProps) 14 | NewAppStackWithDatadogLambda(app, "LambdaGoStack", &AppStackProps{ 15 | StackProps: awscdk.StackProps{ 16 | Env: env(), 17 | }, 18 | }) 19 | 20 | // Creates a Step Functions stack 21 | NewCdkStepFunctionsGoStack(app, "StepFunctionsGoStack", &AppStackProps{ 22 | StackProps: awscdk.StackProps{ 23 | Env: env(), 24 | }, 25 | }) 26 | 27 | app.Synth(nil) 28 | } 29 | 30 | // env determines the AWS environment (account + region) 31 | func env() *awscdk.Environment { 32 | return &awscdk.Environment{ 33 | Account: jsii.String("425362996713"), 34 | Region: jsii.String("us-east-1"), 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /integration_tests/stacks/python/.gitignore: -------------------------------------------------------------------------------- 1 | datadog-cdk-constructs-*.tar.gz -------------------------------------------------------------------------------- /integration_tests/stacks/python/lambda_python_stack.py: -------------------------------------------------------------------------------- 1 | from constructs import Construct 2 | from datadog_cdk_constructs_v2 import DatadogLambda, DatadogLambdaProps 3 | from aws_cdk import App 4 | 5 | from lambda_python_stack_base import LambdaPythonStackBase 6 | 7 | class LambdaPythonStack(LambdaPythonStackBase): 8 | def __init__(self, scope: Construct, id: str, **kwargs) -> None: 9 | super().__init__(scope, id, **kwargs) 10 | 11 | datadog = DatadogLambda( 12 | self, 13 | "Datadog", 14 | dotnet_layer_version=15, 15 | node_layer_version=107, 16 | python_layer_version=89, 17 | extension_layer_version=55, 18 | add_layers=True, 19 | api_key="1234", 20 | enable_datadog_tracing=True, 21 | enable_datadog_asm=True, 22 | flush_metrics_to_logs=True, 23 | site="datadoghq.com", 24 | ) 25 | 26 | # Ensure DatadogLambdaProps can be imported properly 27 | props = DatadogLambdaProps() 28 | datadog.add_lambda_functions(self.lambdaFunctions) 29 | 30 | app = App() 31 | LambdaPythonStack(app, "LambdaPythonStack") 32 | app.synth() -------------------------------------------------------------------------------- /integration_tests/stacks/python/lambda_python_stack_base.py: -------------------------------------------------------------------------------- 1 | from aws_cdk import ( 2 | aws_lambda as _lambda, 3 | aws_lambda_go_alpha as go, 4 | BundlingOptions, 5 | BundlingOutput, 6 | Duration, 7 | Stack, 8 | ) 9 | from constructs import Construct 10 | 11 | 12 | class LambdaPythonStackBase(Stack): 13 | def __init__(self, scope: Construct, id: str, **kwargs) -> None: 14 | super().__init__(scope, id, **kwargs) 15 | 16 | hello_node = _lambda.Function( 17 | self, 18 | "hello-node", 19 | runtime=_lambda.Runtime.NODEJS_20_X, 20 | timeout=Duration.seconds(10), 21 | memory_size=256, 22 | code=_lambda.Code.from_asset( 23 | "../examples/lambda/node", 24 | bundling=BundlingOptions( 25 | image=_lambda.Runtime.NODEJS_20_X.bundling_image, 26 | command=[ 27 | "bash", 28 | "-c", 29 | "cp -aT . /asset-output && npm install --prefix /asset-output", 30 | ], 31 | user="root", 32 | ), 33 | ), 34 | handler="hello.lambda_handler", 35 | ) 36 | 37 | hello_python = _lambda.Function( 38 | self, 39 | "hello-python", 40 | runtime=_lambda.Runtime.PYTHON_3_11, 41 | timeout=Duration.seconds(10), 42 | memory_size=256, 43 | code=_lambda.Code.from_asset( 44 | "../examples/lambda/python", 45 | bundling=BundlingOptions( 46 | image=_lambda.Runtime.PYTHON_3_11.bundling_image, 47 | command=[ 48 | "bash", 49 | "-c", 50 | "pip install -r requirements.txt -t /asset-output && cp -aT . /asset-output", 51 | ], 52 | ), 53 | ), 54 | handler="hello.lambda_handler", 55 | ) 56 | 57 | hello_go = go.GoFunction( 58 | self, 59 | "hello-go", 60 | entry="../examples/lambda/go/hello.go", 61 | runtime=_lambda.Runtime.PROVIDED_AL2, 62 | timeout=Duration.seconds(10), 63 | bundling=go.BundlingOptions( 64 | go_build_flags=['-ldflags "-s -w"'], 65 | ), 66 | ) 67 | 68 | hello_dotnet = _lambda.Function( 69 | self, 70 | "hello-dotnet", 71 | runtime=_lambda.Runtime.DOTNET_8, 72 | handler="HelloWorld::HelloWorld.Handler::SayHi", 73 | timeout=Duration.seconds(10), 74 | memory_size=256, 75 | code=_lambda.Code.from_asset( 76 | "../examples/lambda/dotnet", 77 | bundling=BundlingOptions( 78 | image=_lambda.Runtime.DOTNET_8.bundling_image, 79 | command=[ 80 | '/bin/sh', 81 | '-c', 82 | ' dotnet tool install -g Amazon.Lambda.Tools' + 83 | ' && dotnet build' + 84 | ' && dotnet lambda package --output-package /asset-output/function.zip' 85 | ], 86 | user="root", 87 | output_type=BundlingOutput.ARCHIVED 88 | ), 89 | ), 90 | ) 91 | 92 | self.lambdaFunctions = [hello_node, hello_python, hello_go, hello_dotnet] 93 | -------------------------------------------------------------------------------- /integration_tests/stacks/python/requirements.txt: -------------------------------------------------------------------------------- 1 | aws-cdk-lib~=2.177.0 2 | aws-cdk.aws-lambda-go-alpha~=2.134.0a0 3 | constructs~=10.0.5 4 | datadog_cdk_constructs_v2~=2.0.0 5 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/apigateway-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as apigateway from "aws-cdk-lib/aws-apigateway"; 10 | import * as apigatewayv2 from "aws-cdk-lib/aws-apigatewayv2"; 11 | import * as apigatewayv2_integrations from "aws-cdk-lib/aws-apigatewayv2-integrations"; 12 | import { DatadogAPIGatewayRequestParameters } from "../../../src/index"; 13 | import { DatadogAPIGatewayV2ParameterMapping } from "../../../src/index"; 14 | import { Stack, StackProps, App } from "aws-cdk-lib"; 15 | 16 | export class ExampleStack extends Stack { 17 | constructor(scope: App, id: string, props?: StackProps) { 18 | super(scope, id, props); 19 | 20 | // API Gateway v1 21 | const integrationV1 = new apigateway.Integration({ 22 | type: apigateway.IntegrationType.HTTP_PROXY, 23 | integrationHttpMethod: 'ANY', 24 | options: { connectionType: apigateway.ConnectionType.INTERNET }, 25 | uri: 'https://example.com', 26 | }); 27 | 28 | const restApi = new apigateway.RestApi(this, 'restApi', { 29 | restApiName: 'restApiName', 30 | description: 'API Gateway v1 for forwarding requests to example.com', 31 | deployOptions: { stageName: 'prod' }, 32 | defaultIntegration: integrationV1, 33 | parameters: DatadogAPIGatewayRequestParameters, 34 | }); 35 | 36 | restApi.root.addMethod('ANY'); 37 | const magazines = restApi.root.addResource('magazines'); 38 | magazines.addMethod('ANY'); 39 | const magazine = magazines.addResource('{id}'); 40 | magazine.addMethod('ANY'); 41 | 42 | // API Gateway v2 43 | const integrationV2 = new apigatewayv2_integrations.HttpUrlIntegration( 44 | 'HttpUrlIntegration', 45 | 'https://example.com', 46 | { parameterMapping: DatadogAPIGatewayV2ParameterMapping }, 47 | ); 48 | 49 | const httpApi = new apigatewayv2.HttpApi(this, 'httpApi', { 50 | apiName: 'httpApiName', 51 | description: 'API Gateway v2 for forwarding requests to example.com', 52 | }); 53 | 54 | httpApi.addRoutes({ 55 | path: '/{proxy+}', 56 | methods: [apigatewayv2.HttpMethod.ANY], 57 | integration: integrationV2, 58 | }); 59 | httpApi.addRoutes({ 60 | path: '/books', 61 | methods: [apigatewayv2.HttpMethod.ANY], 62 | integration: integrationV2, 63 | }); 64 | httpApi.addRoutes({ 65 | path: '/books/{id}', 66 | methods: [apigatewayv2.HttpMethod.ANY], 67 | integration: integrationV2, 68 | }); 69 | } 70 | } 71 | 72 | const app = new App(); 73 | const env = { account: "601427279990", region: "sa-east-1" }; 74 | const stack = new ExampleStack(app, "apigateway-stack", { env: env }); 75 | console.log("Stack name: " + stack.stackName); 76 | app.synth(); 77 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/ecs-fargate-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import { Stack, StackProps, App } from "aws-cdk-lib"; 10 | import * as ecs from "aws-cdk-lib/aws-ecs"; 11 | import { DatadogECSFargate } from "../../../src/index"; 12 | 13 | export class ExampleStack extends Stack { 14 | constructor(scope: App, id: string, props?: StackProps) { 15 | super(scope, id, props); 16 | 17 | // Create Datadog ECS Fargate 18 | const ecsDatadog = new DatadogECSFargate({ 19 | apiKey: 'exampleApiKey', 20 | env: 'prod', 21 | apm: { 22 | isEnabled: true, 23 | traceInferredProxyServices: true, 24 | }, 25 | }); 26 | 27 | // Sample Task Definition 28 | const sampleTaskDefinition = ecsDatadog.fargateTaskDefinition( 29 | this, 'sampleTaskDefinition', 30 | { memoryLimitMiB: 512, cpu: 256 }, 31 | ); 32 | sampleTaskDefinition.addContainer('ecsSample', { 33 | image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), 34 | }); 35 | 36 | // Server Task Definition 37 | const serverTaskDefinition = ecsDatadog.fargateTaskDefinition( 38 | this, 'serverTaskDefinition', 39 | { memoryLimitMiB: 512, cpu: 256 }, 40 | { apm: { traceInferredProxyServices: false } }, 41 | ); 42 | serverTaskDefinition.addContainer('nameServer', { 43 | image: ecs.ContainerImage.fromRegistry('ecs-sample-image/name-server'), 44 | }); 45 | serverTaskDefinition.addContainer('helloServer', { 46 | image: ecs.ContainerImage.fromRegistry('ecs-sample-image/hello-server'), 47 | // this value will be overwritten by the task definition 48 | environment: { DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED: 'true' }, 49 | }); 50 | 51 | // Example Task Definition 52 | const exampleTaskDefinition = ecsDatadog.fargateTaskDefinition( 53 | this, 'exampleTaskDefinition', 54 | { memoryLimitMiB: 512, cpu: 256 }, 55 | { apm: { isEnabled: false } }, 56 | ); 57 | exampleTaskDefinition.addContainer('ecsExample', { 58 | image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), 59 | }); 60 | } 61 | } 62 | 63 | const app = new App(); 64 | const env = { account: "601427279990", region: "sa-east-1" }; 65 | const stack = new ExampleStack(app, "ecs-fargate-stack", { env: env }); 66 | console.log("Stack name: " + stack.stackName); 67 | app.synth(); 68 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/lambda-function-arm-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import { Stack, StackProps, App } from "aws-cdk-lib"; 11 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 12 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 13 | import { DatadogLambda } from "../../../src/index"; 14 | import { Architecture } from "aws-cdk-lib/aws-lambda"; 15 | 16 | export class ExampleStack extends Stack { 17 | constructor(scope: App, id: string, props?: StackProps) { 18 | super(scope, id, props); 19 | 20 | const lambdaFunction = new lambda.Function(this, "HelloHandler", { 21 | runtime: lambda.Runtime.NODEJS_18_X, 22 | code: lambda.Code.fromInline("test"), 23 | handler: "lambdaFunction.handler", 24 | architecture: Architecture.ARM_64, 25 | }); 26 | 27 | const restLogGroup = new LogGroup(this, "restLogGroup"); 28 | new LambdaRestApi(this, "rest-test", { 29 | handler: lambdaFunction, 30 | deployOptions: { 31 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 32 | }, 33 | }); 34 | 35 | const datadogLambda = new DatadogLambda(this, "Datadog", { 36 | nodeLayerVersion: 62, 37 | extensionLayerVersion: 10, 38 | enableDatadogTracing: true, 39 | flushMetricsToLogs: true, 40 | sourceCodeIntegration: false, 41 | apiKey: "1234", 42 | site: "datadoghq.com", 43 | }); 44 | datadogLambda.addLambdaFunctions([lambdaFunction]); 45 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup]); 46 | } 47 | } 48 | 49 | const app = new App(); 50 | const env = { account: "601427279990", region: "sa-east-1" }; 51 | const stack = new ExampleStack(app, "lambda-function-arm-stack", { env: env }); 52 | console.log("Stack name: " + stack.stackName); 53 | app.synth(); 54 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/lambda-function-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import { Stack, StackProps, App } from "aws-cdk-lib"; 11 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 12 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 13 | import { DatadogLambda } from "../../../src/index"; 14 | 15 | export class ExampleStack extends Stack { 16 | constructor(scope: App, id: string, props?: StackProps) { 17 | super(scope, id, props); 18 | 19 | const lambdaFunction = new lambda.Function(this, "HelloHandler", { 20 | runtime: lambda.Runtime.NODEJS_18_X, 21 | code: lambda.Code.fromInline("test"), 22 | handler: "lambdaFunction.handler", 23 | }); 24 | 25 | const restLogGroup = new LogGroup(this, "restLogGroup"); 26 | new LambdaRestApi(this, "rest-test", { 27 | handler: lambdaFunction, 28 | deployOptions: { 29 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 30 | }, 31 | }); 32 | 33 | const datadogLambda = new DatadogLambda(this, "Datadog", { 34 | nodeLayerVersion: 62, 35 | extensionLayerVersion: 10, 36 | enableDatadogTracing: true, 37 | flushMetricsToLogs: true, 38 | sourceCodeIntegration: false, 39 | apiKey: "1234", 40 | site: "datadoghq.com", 41 | }); 42 | datadogLambda.addLambdaFunctions([lambdaFunction]); 43 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup]); 44 | } 45 | } 46 | 47 | const app = new App(); 48 | const env = { account: "601427279990", region: "sa-east-1" }; 49 | const stack = new ExampleStack(app, "lambda-function-stack", { env: env }); 50 | console.log("Stack name: " + stack.stackName); 51 | app.synth(); 52 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/lambda-java-function-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 11 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 12 | import { Stack, StackProps, App } from "aws-cdk-lib"; 13 | import { DatadogLambda } from "../../../src/index"; 14 | 15 | export class ExampleStack extends Stack { 16 | constructor(scope: App, id: string, props?: StackProps) { 17 | super(scope, id, props); 18 | 19 | const lambdaJavaFunction = new lambda.Function(this, "HelloHandler", { 20 | runtime: lambda.Runtime.JAVA_11, 21 | code: lambda.Code.fromAsset(__dirname + "/../../lambda"), 22 | handler: "handleRequest", 23 | }); 24 | 25 | const restLogGroup = new LogGroup(this, "restLogGroup"); 26 | new LambdaRestApi(this, "rest-test", { 27 | handler: lambdaJavaFunction, 28 | deployOptions: { 29 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 30 | }, 31 | }); 32 | 33 | const datadogLambda = new DatadogLambda(this, "Datadog", { 34 | javaLayerVersion: 5, 35 | extensionLayerVersion: 25, 36 | enableDatadogTracing: true, 37 | flushMetricsToLogs: true, 38 | sourceCodeIntegration: false, 39 | apiKey: "1234", 40 | site: "datadoghq.com", 41 | }); 42 | datadogLambda.addLambdaFunctions([lambdaJavaFunction]); 43 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup]); 44 | } 45 | } 46 | 47 | const app = new App(); 48 | const env = { account: "601427279990", region: "sa-east-1" }; 49 | const stack = new ExampleStack(app, "lambda-java-function-stack", { env: env }); 50 | console.log("Stack name: " + stack.stackName); 51 | app.synth(); 52 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/lambda-nodejs-function-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; 11 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 12 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 13 | import { Stack, StackProps, App } from "aws-cdk-lib"; 14 | import { DatadogLambda } from "../../../src/index"; 15 | 16 | export class ExampleStack extends Stack { 17 | constructor(scope: App, id: string, props?: StackProps) { 18 | super(scope, id, props); 19 | 20 | const lambdaNodejsFunction = new NodejsFunction(this, "HelloHandler", { 21 | runtime: lambda.Runtime.NODEJS_18_X, 22 | entry: __dirname + "/../../lambda/example-lambda.js", 23 | handler: "handler", 24 | }); 25 | 26 | const restLogGroup = new LogGroup(this, "restLogGroup"); 27 | new LambdaRestApi(this, "rest-test", { 28 | handler: lambdaNodejsFunction, 29 | deployOptions: { 30 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 31 | }, 32 | }); 33 | 34 | const datadogLambda = new DatadogLambda(this, "Datadog", { 35 | nodeLayerVersion: 62, 36 | extensionLayerVersion: 10, 37 | enableDatadogTracing: true, 38 | flushMetricsToLogs: true, 39 | sourceCodeIntegration: false, 40 | apiKey: "1234", 41 | site: "datadoghq.com", 42 | }); 43 | datadogLambda.addLambdaFunctions([lambdaNodejsFunction]); 44 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup]); 45 | } 46 | } 47 | 48 | const app = new App(); 49 | const env = { account: "601427279990", region: "sa-east-1" }; 50 | const stack = new ExampleStack(app, "lambda-nodejs-function-stack", { env: env }); 51 | console.log("Stack name: " + stack.stackName); 52 | app.synth(); 53 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/lambda-provided-arm-stack.ts: -------------------------------------------------------------------------------- 1 | import * as lambda from "aws-cdk-lib/aws-lambda"; 2 | import * as s3 from "aws-cdk-lib/aws-s3"; 3 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 4 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 5 | import { Stack, StackProps, App } from "aws-cdk-lib"; 6 | import { DatadogLambda } from "../../../src/index"; 7 | 8 | export class ExampleStack extends Stack { 9 | constructor(scope: App, id: string, props?: StackProps) { 10 | super(scope, id, props); 11 | 12 | const s3Bucket = new s3.Bucket(this, "exampleBucket", { 13 | objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED, 14 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 15 | }); 16 | 17 | const providedLambda = new lambda.Function(this, "HelloHandler", { 18 | runtime: lambda.Runtime.PROVIDED_AL2, 19 | code: lambda.Code.fromBucket(s3Bucket, "fake-key-for-test"), 20 | handler: "handler.handler", 21 | architecture: lambda.Architecture.ARM_64, 22 | }); 23 | 24 | s3Bucket.grantRead(providedLambda); 25 | 26 | const restLogGroup = new LogGroup(this, "restLogGroup"); 27 | new LambdaRestApi(this, "rest-test", { 28 | handler: providedLambda, 29 | deployOptions: { 30 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 31 | }, 32 | }); 33 | 34 | const datadogLambda = new DatadogLambda(this, "Datadog", { 35 | extensionLayerVersion: 49, 36 | apiKey: "1234", 37 | site: "datadoghq.com", 38 | sourceCodeIntegration: false, 39 | }); 40 | datadogLambda.addLambdaFunctions([providedLambda]); 41 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup]); 42 | } 43 | } 44 | 45 | const app = new App(); 46 | const env = { account: "601427279990", region: "sa-east-1" }; 47 | const stack = new ExampleStack(app, "lambda-provided-arm-stack", { env: env }); 48 | console.log("Stack name: " + stack.stackName); 49 | app.synth(); 50 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/lambda-provided-stack.ts: -------------------------------------------------------------------------------- 1 | import * as lambda from "aws-cdk-lib/aws-lambda"; 2 | import * as s3 from "aws-cdk-lib/aws-s3"; 3 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 4 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 5 | import { Stack, StackProps, App } from "aws-cdk-lib"; 6 | import { DatadogLambda } from "../../../src/index"; 7 | 8 | export class ExampleStack extends Stack { 9 | constructor(scope: App, id: string, props?: StackProps) { 10 | super(scope, id, props); 11 | 12 | const s3Bucket = new s3.Bucket(this, "exampleBucket", { 13 | objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED, 14 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 15 | }); 16 | 17 | const providedLambda = new lambda.Function(this, "HelloHandler", { 18 | runtime: lambda.Runtime.PROVIDED_AL2, 19 | code: lambda.Code.fromBucket(s3Bucket, "fake-key-for-test"), 20 | handler: "handler.handler", 21 | }); 22 | 23 | s3Bucket.grantRead(providedLambda); 24 | 25 | const restLogGroup = new LogGroup(this, "restLogGroup"); 26 | new LambdaRestApi(this, "rest-test", { 27 | handler: providedLambda, 28 | deployOptions: { 29 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 30 | }, 31 | }); 32 | 33 | const datadogLambda = new DatadogLambda(this, "Datadog", { 34 | extensionLayerVersion: 49, 35 | apiKey: "1234", 36 | site: "datadoghq.com", 37 | sourceCodeIntegration: false, 38 | }); 39 | datadogLambda.addLambdaFunctions([providedLambda]); 40 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup]); 41 | } 42 | } 43 | 44 | const app = new App(); 45 | const env = { account: "601427279990", region: "sa-east-1" }; 46 | const stack = new ExampleStack(app, "lambda-provided-stack", { env: env }); 47 | console.log("Stack name: " + stack.stackName); 48 | app.synth(); 49 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/lambda-python-function-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import { PythonFunction } from "@aws-cdk/aws-lambda-python-alpha"; 11 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 12 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 13 | import { Stack, StackProps, App } from "aws-cdk-lib"; 14 | import { DatadogLambda } from "../../../src/index"; 15 | 16 | export class ExampleStack extends Stack { 17 | constructor(scope: App, id: string, props?: StackProps) { 18 | super(scope, id, props); 19 | 20 | const lambdaPythonFunction = new PythonFunction(this, "HelloHandler", { 21 | runtime: lambda.Runtime.PYTHON_3_7, 22 | entry: __dirname + "/../../../../lambda", 23 | index: "example-python.py", 24 | handler: "handler", 25 | }); 26 | 27 | const restLogGroup = new LogGroup(this, "restLogGroup"); 28 | new LambdaRestApi(this, "rest-test", { 29 | handler: lambdaPythonFunction, 30 | deployOptions: { 31 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 32 | }, 33 | }); 34 | 35 | const datadogLambda = new DatadogLambda(this, "Datadog", { 36 | pythonLayerVersion: 46, 37 | extensionLayerVersion: 10, 38 | enableDatadogTracing: true, 39 | flushMetricsToLogs: true, 40 | sourceCodeIntegration: false, 41 | apiKey: "1234", 42 | site: "datadoghq.com", 43 | }); 44 | datadogLambda.addLambdaFunctions([lambdaPythonFunction]); 45 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup]); 46 | } 47 | } 48 | 49 | const app = new App(); 50 | const env = { account: "601427279990", region: "sa-east-1" }; 51 | const stack = new ExampleStack(app, "lambda-python-function-stack", { env: env }); 52 | console.log("Stack name: " + stack.stackName); 53 | app.synth(); 54 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/lambda-singleton-function-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import { Stack, StackProps, App } from "aws-cdk-lib"; 11 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 12 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 13 | import { DatadogLambda } from "../../../src/index"; 14 | 15 | export class ExampleStack extends Stack { 16 | constructor(scope: App, id: string, props?: StackProps) { 17 | super(scope, id, props); 18 | 19 | const singletonLambdaFunction = new lambda.SingletonFunction(this, "HelloHandler", { 20 | runtime: lambda.Runtime.NODEJS_18_X, 21 | code: lambda.Code.fromInline("test"), 22 | handler: "lambdaFunction.handler", 23 | uuid: "b55587fe-6985-4c28-ab51-4d0edb1ba8a1", 24 | }); 25 | 26 | const restLogGroup = new LogGroup(this, "restLogGroup"); 27 | new LambdaRestApi(this, "rest-test", { 28 | handler: singletonLambdaFunction, 29 | deployOptions: { 30 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 31 | }, 32 | }); 33 | 34 | const datadogLambda = new DatadogLambda(this, "Datadog", { 35 | nodeLayerVersion: 62, 36 | extensionLayerVersion: 10, 37 | enableDatadogTracing: true, 38 | flushMetricsToLogs: true, 39 | sourceCodeIntegration: false, 40 | apiKey: "1234", 41 | site: "datadoghq.com", 42 | }); 43 | datadogLambda.addLambdaFunctions([singletonLambdaFunction]); 44 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup]); 45 | } 46 | } 47 | 48 | const app = new App(); 49 | const env = { account: "601427279990", region: "sa-east-1" }; 50 | const stack = new ExampleStack(app, "lambda-singleton-function-stack", { env: env }); 51 | console.log("Stack name: " + stack.stackName); 52 | app.synth(); 53 | -------------------------------------------------------------------------------- /integration_tests/stacks/typescript/step-function-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import * as sfn from "aws-cdk-lib/aws-stepfunctions"; 11 | import { Duration, Stack, StackProps, App } from "aws-cdk-lib"; 12 | import { Construct } from "constructs"; 13 | import { DatadogStepFunctions, DatadogLambda } from "../../../src/index"; 14 | import * as tasks from "aws-cdk-lib/aws-stepfunctions-tasks"; 15 | 16 | export class ExampleStack extends Stack { 17 | constructor(scope: Construct, id: string, props?: StackProps) { 18 | super(scope, id, props); 19 | 20 | console.log("Creating Hello World TypeScript stack"); 21 | 22 | /* Set up the child state machine */ 23 | 24 | const passState = new sfn.Pass(this, "PassState"); 25 | const waitState = new sfn.Wait(this, "WaitState", { time: sfn.WaitTime.duration(Duration.seconds(1)) }); 26 | const successState = new sfn.Succeed(this, "SuccessState"); 27 | 28 | const childStateMachine = new sfn.StateMachine(this, "CdkTypeScriptTestChildStateMachine", { 29 | definitionBody: sfn.DefinitionBody.fromChainable(passState.next(waitState).next(successState)), 30 | }); 31 | 32 | /* Set up the parent state machine */ 33 | 34 | const invokeChildStateMachineTask = new tasks.StepFunctionsStartExecution(this, "InvokeChildStateMachineTask", { 35 | stateMachine: childStateMachine, 36 | input: sfn.TaskInput.fromObject( 37 | DatadogStepFunctions.buildStepFunctionTaskInputToMergeTraces({ "custom-key": "custom-value" }), 38 | ), 39 | }); 40 | 41 | const helloLambdaFunction = new lambda.Function(this, "hello-python", { 42 | runtime: lambda.Runtime.PYTHON_3_12, 43 | handler: "index.handler", 44 | code: lambda.Code.fromInline(` 45 | def handler(event, context): 46 | return "Hello, world!" 47 | `), 48 | }); 49 | 50 | const lambdaTask = new tasks.LambdaInvoke(this, "MyLambdaTask", { 51 | lambdaFunction: helloLambdaFunction, 52 | payload: sfn.TaskInput.fromObject(DatadogStepFunctions.buildLambdaPayloadToMergeTraces()), 53 | }); 54 | 55 | const parentStateMachine = new sfn.StateMachine(this, "CdkTypeScriptTestStateMachine", { 56 | definitionBody: sfn.DefinitionBody.fromChainable(lambdaTask.next(invokeChildStateMachineTask)), 57 | }); 58 | 59 | /* Instrument the lambda functions and the state machines */ 60 | 61 | console.log("Instrumenting Step Functions in TypeScript stack with Datadog"); 62 | 63 | const datadogSfn = new DatadogStepFunctions(this, "DatadogSfn", { 64 | env: "dev", 65 | service: "cdk-test-service", 66 | version: "1.0.0", 67 | forwarderArn: "arn:test:forwarder:sa-east-1:12345678:1", 68 | tags: "custom-tag-1:tag-value-1,custom-tag-2:tag-value-2", 69 | }); 70 | datadogSfn.addStateMachines([childStateMachine, parentStateMachine]); 71 | 72 | const datadogLambda = new DatadogLambda(this, "DatadogLambda", { 73 | pythonLayerVersion: 101, 74 | extensionLayerVersion: 65, 75 | addLayers: true, 76 | apiKey: "1234", 77 | enableDatadogTracing: true, 78 | enableDatadogASM: true, 79 | flushMetricsToLogs: true, 80 | site: "datadoghq.com", 81 | env: "dev", 82 | service: "cdk-test-service", 83 | version: "1.0.0", 84 | }); 85 | datadogLambda.addLambdaFunctions([helloLambdaFunction]); 86 | } 87 | } 88 | 89 | const app = new App(); 90 | const env = { account: "601427279990", region: "sa-east-1" }; 91 | const stack = new ExampleStack(app, "step-function-stack", { env: env }); 92 | console.log("Stack name: " + stack.stackName); 93 | app.synth(); 94 | -------------------------------------------------------------------------------- /integration_tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "testlib", 4 | "rootDirs": ["stacks", "lambda", "../src"], 5 | "alwaysStrict": true, 6 | "declaration": true, 7 | "experimentalDecorators": true, 8 | "incremental": true, 9 | "inlineSourceMap": true, 10 | "inlineSources": true, 11 | "lib": [ 12 | "es2018" 13 | ], 14 | "module": "CommonJS", 15 | "moduleResolution": "node", 16 | "newLine": "lf", 17 | "noEmitOnError": true, 18 | "noFallthroughCasesInSwitch": true, 19 | "noImplicitAny": true, 20 | "noImplicitReturns": true, 21 | "noImplicitThis": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "resolveJsonModule": true, 25 | "strict": true, 26 | "strictNullChecks": true, 27 | "strictPropertyInitialization": true, 28 | "stripInternal": false, 29 | "target": "ES2018", 30 | "composite": false, 31 | "tsBuildInfoFile": "testlib/tsconfig.tsbuildinfo" 32 | }, 33 | "include": [ 34 | "stacks/**/*.ts", 35 | "lambda/**/*.ts", 36 | "../version.json" 37 | ], 38 | "exclude": [ 39 | "../node_modules" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /scripts/fix-version.js: -------------------------------------------------------------------------------- 1 | // Helper script used to fix package.json version resetting on builds, and helping bump version.json after releases 2 | 3 | // Copies the version from version.json into package.json 4 | var fs = require("fs"); 5 | var path = require("path"); 6 | 7 | version_file_path = path.join(__dirname, "..", "version.json"); 8 | package_file_path = path.join(__dirname, "..", "package.json"); 9 | 10 | var version_json = require(version_file_path); 11 | var package_json = require(package_file_path); 12 | 13 | package_json.version = version_json.version; 14 | fs.writeFileSync(package_file_path, JSON.stringify(package_json, null, 2)); 15 | -------------------------------------------------------------------------------- /scripts/generate_third_party_license_file.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import json 3 | import re 4 | import shlex 5 | import subprocess 6 | 7 | REPO_EXCEPTIONS = {"eyes": "https://github.com/cloudhead/eyes.js"} 8 | 9 | COPYRIGHT_EXCEPTIONS = ["aws-sdk", "datadog-lambda-js"] 10 | 11 | """ 12 | Exceptions to this scripts assumptions about the formatting of LICENSE files: 13 | querystring contains the whole license 14 | colors.js doesn't have "Copyright" starting at the beginning of the line (https://github.com/Marak/colors.js/blob/master/LICENSE) 15 | cycles uses the JSON license (https://github.com/dscape/cycle) 16 | aws-xray-sdk puts the copyright string in NOTICE.txt instead of in LICENSE 17 | datadog-lambda-js doesn't put a copyright string in the LICENSE file 18 | aws-sdk-js uses the same format ^ 19 | base64-js misses the name after the copyright year (github.com/beatgammit/base64-js) 20 | querystring puts the whole license in one line 21 | """ 22 | 23 | def get_repo_url(dep_name, dep_meta): 24 | repo_url = dep_meta.get("repository", REPO_EXCEPTIONS.get(dep_name, "NO REPO")) 25 | if repo_url.startswith("https"): 26 | return re.search(r"https:\/\/(.*)", repo_url).group(1) 27 | return repo_url 28 | 29 | 30 | if __name__ == "__main__": 31 | raw_output = subprocess.check_output( 32 | shlex.split("license-checker --json --production --start ..") 33 | ) 34 | deps = json.loads(raw_output) 35 | alphabetized_dep_names = sorted(deps.keys()) 36 | 37 | formatted_deps = [] 38 | for dep in alphabetized_dep_names: 39 | dep_meta = deps[dep] 40 | dep_name = re.search(r"([\w-]+)@", dep).group(1) 41 | repo_url = get_repo_url(dep_name, dep_meta) 42 | license = dep_meta.get("licenses", "LICENSE NOT FOUND") 43 | 44 | if "Custom" in license: 45 | print("Custom license for {}".format(dep_name)) 46 | 47 | # Extract the "Copyright ..." line from the license file. 48 | # Naively handles multi-line copyrights starting with "Copyright" 49 | # and ending with two newlines. 50 | license_file = dep_meta.get("licenseFile", None) 51 | dep_copyright = "" 52 | if license_file: 53 | with open(license_file) as f: 54 | contents = f.read() 55 | # https://stackoverflow.com/a/52347904 56 | matches = re.findall(r"(Copyright.*(\n\S.*)*)", contents) 57 | if len(matches) > 0: 58 | dep_copyright = matches[0][0].replace("\n", " ") 59 | else: 60 | print("No license file for {}".format(dep_name)) 61 | 62 | formatted_deps.append( 63 | { 64 | "Component": dep_name, 65 | "Origin": repo_url, 66 | "License": license, 67 | "Copyright": dep_copyright, 68 | } 69 | ) 70 | 71 | with open("../LICENSE-3rdparty.csv", "w") as csv_file: 72 | fieldnames = ["Component", "Origin", "License", "Copyright"] 73 | writer = csv.DictWriter(csv_file, fieldnames=fieldnames) 74 | writer.writeheader() 75 | for dep in formatted_deps: 76 | writer.writerow(dep) 77 | -------------------------------------------------------------------------------- /src/apigateway/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./parameters"; 2 | -------------------------------------------------------------------------------- /src/apigateway/parameters.ts: -------------------------------------------------------------------------------- 1 | import * as apigatewayv2 from "aws-cdk-lib/aws-apigatewayv2"; 2 | 3 | const DatadogAPIGatewayRequestParameters = { 4 | "integration.request.header.x-dd-proxy": "'aws-apigateway'", 5 | "integration.request.header.x-dd-proxy-request-time-ms": "context.requestTimeEpoch", 6 | "integration.request.header.x-dd-proxy-domain-name": "context.domainName", 7 | "integration.request.header.x-dd-proxy-httpmethod": "context.httpMethod", 8 | "integration.request.header.x-dd-proxy-path": "context.path", 9 | "integration.request.header.x-dd-proxy-stage": "context.stage", 10 | }; 11 | 12 | function appendDatadogHeaders(existingMapping?: apigatewayv2.ParameterMapping): apigatewayv2.ParameterMapping { 13 | if (!existingMapping) { 14 | existingMapping = new apigatewayv2.ParameterMapping(); 15 | } 16 | return existingMapping 17 | .appendHeader("x-dd-proxy", apigatewayv2.MappingValue.custom("aws-apigateway")) 18 | .appendHeader("x-dd-proxy-request-time-ms", apigatewayv2.MappingValue.custom("${context.requestTimeEpoch}000")) 19 | .appendHeader("x-dd-proxy-domain-name", apigatewayv2.MappingValue.custom("$context.domainName")) 20 | .appendHeader("x-dd-proxy-httpmethod", apigatewayv2.MappingValue.custom("$context.httpMethod")) 21 | .appendHeader("x-dd-proxy-path", apigatewayv2.MappingValue.custom("$context.path")) 22 | .appendHeader("x-dd-proxy-stage", apigatewayv2.MappingValue.custom("$context.stage")); 23 | } 24 | 25 | const DatadogAPIGatewayV2ParameterMapping = appendDatadogHeaders(); 26 | 27 | export { DatadogAPIGatewayRequestParameters, DatadogAPIGatewayV2ParameterMapping, appendDatadogHeaders }; 28 | -------------------------------------------------------------------------------- /src/ecs/constants.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import { Duration } from "aws-cdk-lib"; 10 | import { DatadogECSBaseProps, Cardinality } from "./interfaces"; 11 | 12 | /** 13 | * Default props for the Datadog ECS Fargate construct 14 | */ 15 | export const DatadogEcsBaseDefaultProps: DatadogECSBaseProps = { 16 | registry: "public.ecr.aws/datadog/agent", 17 | imageVersion: "latest", 18 | 19 | apm: { 20 | isEnabled: true, 21 | isSocketEnabled: true, 22 | traceInferredProxyServices: false, 23 | }, 24 | 25 | dogstatsd: { 26 | isEnabled: true, 27 | isSocketEnabled: true, 28 | isOriginDetectionEnabled: true, 29 | dogstatsdCardinality: Cardinality.ORCHESTRATOR, 30 | }, 31 | 32 | isDatadogEssential: false, 33 | isDatadogDependencyEnabled: false, 34 | datadogHealthCheck: { 35 | command: ["/probe.sh"], 36 | interval: Duration.seconds(10), 37 | retries: 3, 38 | startPeriod: Duration.seconds(60), 39 | timeout: Duration.seconds(5), 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /src/ecs/environment.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | export class EnvVarManager { 10 | private envVars: Record = {}; 11 | private overwrittenKeys: Set = new Set(); 12 | 13 | constructor(defaultEnvVars: Record = {}) { 14 | this.addAll(defaultEnvVars); 15 | } 16 | 17 | /** 18 | * Adds an environment variable if the value is not undefined. 19 | * If the key already exists, it records that it has been overwritten. 20 | */ 21 | add(key: string, value: string | undefined): void { 22 | if (value === undefined) { 23 | return; 24 | } 25 | if (this.envVars.hasOwnProperty(key)) { 26 | this.overwrittenKeys.add(key); 27 | } 28 | this.envVars[key] = value; 29 | } 30 | 31 | /** 32 | * Adds all environment variables from a record. 33 | */ 34 | addAll(envVars: Record | undefined): void { 35 | if (envVars === undefined) { 36 | return; 37 | } 38 | for (const [key, value] of Object.entries(envVars)) { 39 | this.add(key, value); 40 | } 41 | } 42 | 43 | /** 44 | * Retrieves an environment variable by key. 45 | */ 46 | retrieve(key: string): string | undefined { 47 | return this.envVars[key]; 48 | } 49 | 50 | /** 51 | * Returns all stored environment variables. 52 | */ 53 | retrieveAll(): Record { 54 | return { ...this.envVars }; 55 | } 56 | 57 | /** 58 | * Returns a list of keys that have been overwritten. 59 | */ 60 | retrieveOverwrittenKeys(): string[] { 61 | return Array.from(this.overwrittenKeys); 62 | } 63 | 64 | /** 65 | * Returns a string representation of the environment variables. 66 | */ 67 | toString(): string { 68 | return JSON.stringify(this.envVars); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/ecs/fargate/constants.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import { Duration } from "aws-cdk-lib"; 10 | import { FirelensConfigFileType } from "aws-cdk-lib/aws-ecs"; 11 | import { DatadogECSFargateProps, DatadogECSLogDriverProps, LoggingType } from "./interfaces"; 12 | import { DatadogEcsBaseDefaultProps } from "../constants"; 13 | 14 | /** 15 | * Default environment variables for the Agent in Fargate Tasks 16 | */ 17 | export const FargateDefaultEnvVars = { 18 | DD_ECS_TASK_COLLECTION_ENABLED: "true", 19 | ECS_FARGATE: "true", 20 | }; 21 | 22 | /** 23 | * Default log driver configuration for ECS Fargate 24 | */ 25 | const DatadogECSLogDriverDefaultProps: DatadogECSLogDriverProps = { 26 | hostEndpoint: "http-intake.logs.datadoghq.com", 27 | }; 28 | 29 | /** 30 | * Default props for the Datadog ECS Fargate construct 31 | */ 32 | export const DatadogEcsFargateDefaultProps: DatadogECSFargateProps = { 33 | ...DatadogEcsBaseDefaultProps, 34 | logCollection: { 35 | isEnabled: false, 36 | loggingType: LoggingType.FLUENTBIT, 37 | fluentbitConfig: { 38 | logDriverConfig: DatadogECSLogDriverDefaultProps, 39 | isLogRouterEssential: false, 40 | isLogRouterDependencyEnabled: false, 41 | logRouterHealthCheck: { 42 | // Note: below is the recommended command for the health check, 43 | // however, this requires changes to the fluent-bit.conf file to 44 | // expose the health check endpoint. To ease configuration, the 45 | // default command will only check that the container successfully 46 | // started via "exit 0". 47 | // command: ["curl -f http://127.0.0.1:2020/api/v1/health || exit 1"], 48 | command: ["exit 0"], 49 | interval: Duration.seconds(5), 50 | retries: 3, 51 | startPeriod: Duration.seconds(15), 52 | timeout: Duration.seconds(5), 53 | }, 54 | registry: "public.ecr.aws/aws-observability/aws-for-fluent-bit", 55 | imageVersion: "stable", 56 | firelensOptions: { 57 | isParseJson: false, 58 | }, 59 | }, 60 | }, 61 | cws: { 62 | isEnabled: false, 63 | }, 64 | }; 65 | 66 | /** 67 | * Default CWS entrypoint prefix for application containers 68 | */ 69 | export const EntryPointPrefixCWS = ["/cws-instrumentation-volume/cws-instrumentation", "trace", "--"]; 70 | 71 | /** 72 | * Config file type for the Firelens configuration parsing JSON 73 | */ 74 | export const ParseJsonFirelensConfigFileType = FirelensConfigFileType.FILE; 75 | 76 | /** 77 | * Config file path for the Firelens configuration parsing JSON 78 | */ 79 | export const ParseJsonFirelensConfigFileValue = "/fluent-bit/configs/parse-json.conf"; 80 | -------------------------------------------------------------------------------- /src/ecs/fargate/environment.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import log from "loglevel"; 10 | import { FargateDefaultEnvVars } from "./constants"; 11 | import { DatadogECSFargateProps } from "./interfaces"; 12 | import * as versionJson from "../../../version.json"; 13 | import { EnvVarManager } from "../environment"; 14 | 15 | export class FargateEnvVarManager extends EnvVarManager { 16 | constructor(props: DatadogECSFargateProps) { 17 | super(FargateDefaultEnvVars); 18 | 19 | this.addAll(props.environmentVariables); 20 | 21 | this.add("DD_INSTALL_INFO_TOOL", "cdk"); 22 | this.add("DD_INSTALL_INFO_TOOL_VERSION", "datadog-cdk-constructs"); 23 | this.add("DD_INSTALL_INFO_INSTALLER_VERSION", versionJson.version); 24 | 25 | this.add("DD_API_KEY", props.apiKey); 26 | this.add("DD_SITE", props.site); 27 | this.add("DD_ENV", props.env); 28 | this.add("DD_SERVICE", props.service); 29 | this.add("DD_VERSION", props.version); 30 | this.add("DD_CHECKS_TAG_CARDINALITY", props.checksCardinality); 31 | if (props.globalTags && this.retrieve("DD_TAGS")) { 32 | log.debug( 33 | "Global tags (DD_TAGS) are set in both the environment variable" + 34 | "and the props. The environment variable will be overwritten.", 35 | ); 36 | } 37 | this.add("DD_TAGS", props.globalTags); 38 | this.add("DD_CLUSTER_NAME", props.clusterName); 39 | 40 | if (props.dogstatsd!.isOriginDetectionEnabled) { 41 | this.add("DD_DOGSTATSD_ORIGIN_DETECTION", "true"); 42 | this.add("DD_DOGSTATSD_ORIGIN_DETECTION_CLIENT", "true"); 43 | } 44 | this.add("DD_DOGSTATSD_TAG_CARDINALITY", props.dogstatsd!.dogstatsdCardinality); 45 | 46 | if (props.cws!.isEnabled) { 47 | this.add("DD_RUNTIME_SECURITY_CONFIG_ENABLED", "true"); 48 | this.add("DD_RUNTIME_SECURITY_CONFIG_EBPFLESS_ENABLED", "true"); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/ecs/fargate/interfaces.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import { HealthCheck, FirelensOptions } from "aws-cdk-lib/aws-ecs"; 10 | import { CWSFeatureConfig, DatadogECSBaseProps, LogCollectionFeatureConfig } from "../interfaces"; 11 | 12 | export interface DatadogECSFargateProps extends DatadogECSBaseProps { 13 | readonly logCollection?: FargateLogCollectionFeatureConfig; 14 | readonly cws?: FargateCWSFeatureConfig; 15 | } 16 | 17 | export interface FargateCWSFeatureConfig extends CWSFeatureConfig { 18 | /** 19 | * The minimum number of CPU units to reserve 20 | * for the Datadog CWS init container. 21 | */ 22 | readonly cpu?: number; 23 | /** 24 | * The amount (in MiB) of memory to present 25 | * to the Datadog CWS init container. 26 | */ 27 | readonly memoryLimitMiB?: number; 28 | } 29 | 30 | export interface FargateLogCollectionFeatureConfig extends LogCollectionFeatureConfig { 31 | /** 32 | * Type of log collection. 33 | */ 34 | readonly loggingType?: LoggingType; 35 | /** 36 | * Fluentbit log collection configuration. 37 | */ 38 | readonly fluentbitConfig?: FluentbitConfig; 39 | } 40 | 41 | export interface FluentbitConfig { 42 | /** 43 | * Configuration for the Datadog log driver. 44 | */ 45 | readonly logDriverConfig?: DatadogECSLogDriverProps; 46 | /** 47 | * Firelens options for the Fluentbit container. 48 | */ 49 | readonly firelensOptions?: DatadogFirelensOptions; 50 | /** 51 | * Makes the log router essential. 52 | */ 53 | readonly isLogRouterEssential?: boolean; 54 | /** 55 | * Enables the log router health check. 56 | */ 57 | readonly isLogRouterDependencyEnabled?: boolean; 58 | /** 59 | * Health check configuration for the log router. 60 | */ 61 | readonly logRouterHealthCheck?: HealthCheck; 62 | /** 63 | * The registry to pull the Fluentbit container image from. 64 | */ 65 | readonly registry?: string; 66 | /** 67 | * The version of the Fluentbit container image to use. 68 | */ 69 | readonly imageVersion?: string; 70 | /** 71 | * The minimum number of CPU units to reserve 72 | * for the Datadog fluent-bit container. 73 | */ 74 | readonly cpu?: number; 75 | /** 76 | * The amount (in MiB) of memory to present 77 | * to the Datadog fluent-bit container. 78 | */ 79 | readonly memoryLimitMiB?: number; 80 | } 81 | 82 | /** 83 | * Type of datadog logging configuration. 84 | */ 85 | export enum LoggingType { 86 | /** 87 | * Forwarding logs to Datadog using Fluentbit container. 88 | * Only compatible on Linux. 89 | */ 90 | FLUENTBIT = "fluentbit", 91 | /** 92 | * Currently unsupported within this construct, 93 | * must configure manually on containers. 94 | * https://docs.datadoghq.com/integrations/ecs_fargate/?tab=webui#aws-log-driver 95 | */ 96 | // LAMBDAFORWARDER = "lambda", 97 | } 98 | 99 | /** 100 | * Datadog Fluentbit log driver configuration. 101 | * https://docs.fluentbit.io/manual/pipeline/outputs/datadog 102 | */ 103 | export interface DatadogECSLogDriverProps { 104 | readonly hostEndpoint?: string; 105 | readonly tls?: string; 106 | readonly compress?: string; 107 | readonly serviceName?: string; 108 | readonly sourceName?: string; 109 | readonly messageKey?: string; 110 | } 111 | 112 | export interface DatadogFirelensOptions extends FirelensOptions { 113 | /** 114 | * Overrides the config file type and value to support JSON parsing. 115 | */ 116 | readonly isParseJson?: boolean; 117 | } 118 | -------------------------------------------------------------------------------- /src/ecs/fargate/internal.interfaces.ts: -------------------------------------------------------------------------------- 1 | import { Secret } from "aws-cdk-lib/aws-ecs"; 2 | import { EnvVarManager } from "../environment"; 3 | import { DatadogECSFargateProps } from "./interfaces"; 4 | 5 | /** 6 | * Internal props for the Datadog ECS Fargate construct. 7 | */ 8 | export interface DatadogECSFargateInternalProps extends DatadogECSFargateProps { 9 | readonly envVarManager: EnvVarManager; 10 | readonly isLinux: boolean; 11 | readonly isSocketRequired: boolean; 12 | readonly isProtocolRequired: boolean; 13 | readonly datadogSecret?: Secret; 14 | } 15 | -------------------------------------------------------------------------------- /src/ecs/fargate/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import log from "loglevel"; 10 | import { ParseJsonFirelensConfigFileType, ParseJsonFirelensConfigFileValue } from "./constants"; 11 | import { DatadogECSFargateProps, LoggingType } from "./interfaces"; 12 | import { DatadogECSFargateInternalProps } from "./internal.interfaces"; 13 | 14 | export function mergeFargateProps( 15 | lowerPrecedence: DatadogECSFargateProps, 16 | higherPrecedence: DatadogECSFargateProps | undefined, 17 | ): DatadogECSFargateProps { 18 | if (higherPrecedence === undefined) { 19 | return lowerPrecedence; 20 | } 21 | 22 | const newProps = { 23 | ...lowerPrecedence, 24 | ...higherPrecedence, 25 | }; 26 | 27 | newProps.apm = { 28 | ...lowerPrecedence.apm, 29 | ...higherPrecedence.apm, 30 | }; 31 | newProps.dogstatsd = { 32 | ...lowerPrecedence.dogstatsd, 33 | ...higherPrecedence.dogstatsd, 34 | }; 35 | const firelensOptions = { 36 | ...lowerPrecedence.logCollection?.fluentbitConfig?.firelensOptions, 37 | ...higherPrecedence.logCollection?.fluentbitConfig?.firelensOptions, 38 | }; 39 | if (firelensOptions.isParseJson === true) { 40 | firelensOptions.configFileType = ParseJsonFirelensConfigFileType; 41 | firelensOptions.configFileValue = ParseJsonFirelensConfigFileValue; 42 | } 43 | newProps.logCollection = { 44 | ...lowerPrecedence.logCollection, 45 | ...higherPrecedence.logCollection, 46 | fluentbitConfig: { 47 | ...lowerPrecedence.logCollection?.fluentbitConfig, 48 | ...higherPrecedence.logCollection?.fluentbitConfig, 49 | logDriverConfig: { 50 | ...lowerPrecedence.logCollection?.fluentbitConfig?.logDriverConfig, 51 | ...higherPrecedence.logCollection?.fluentbitConfig?.logDriverConfig, 52 | }, 53 | firelensOptions: firelensOptions, 54 | }, 55 | }; 56 | newProps.cws = { 57 | ...lowerPrecedence.cws, 58 | ...higherPrecedence.cws, 59 | }; 60 | 61 | return newProps; 62 | } 63 | 64 | export function validateECSFargateProps(props: DatadogECSFargateInternalProps): void { 65 | if (process.env.DD_CDK_BYPASS_VALIDATION) { 66 | log.debug("Bypassing props validation..."); 67 | return; 68 | } 69 | 70 | if (props.logCollection === undefined) { 71 | throw new Error("The `logCollection` property must be defined."); 72 | } 73 | 74 | if (props.logCollection.isEnabled) { 75 | if (props.logCollection.loggingType === undefined) { 76 | throw new Error("The `loggingType` property must be defined when logging enabled."); 77 | } 78 | if (props.logCollection.loggingType === LoggingType.FLUENTBIT) { 79 | if (props.isLinux === false) { 80 | throw new Error("Fluent Bit logging is only supported on Linux."); 81 | } 82 | if (props.logCollection.fluentbitConfig === undefined) { 83 | throw new Error("The `fluentbitConfig` property must be defined when fluentbit logging enabled."); 84 | } 85 | if (props.logCollection.fluentbitConfig.logDriverConfig === undefined) { 86 | throw new Error("The `logDriverConfig` property must be defined when logging enabled."); 87 | } 88 | if (props.logCollection.fluentbitConfig.firelensOptions === undefined) { 89 | throw new Error("The `firelensOptions` property must be defined when logging enabled."); 90 | } 91 | } 92 | } 93 | 94 | if (props.cws === undefined) { 95 | throw new Error("The `cws` property must be defined."); 96 | } 97 | 98 | if (props.cws?.isEnabled) { 99 | if (props.isLinux === false) { 100 | throw new Error("CWS is only supported on Linux."); 101 | } 102 | if (props.isDatadogDependencyEnabled === false) { 103 | throw new Error( 104 | "CWS configuration highly recommends Datadog Agent dependency enabled. The CWS tracer eventually exits the application if it can't connect to the Datadog Agent.", 105 | ); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/ecs/index.ts: -------------------------------------------------------------------------------- 1 | // External index 2 | export * from "./interfaces"; 3 | export * from "./fargate/interfaces"; 4 | export * from "./fargate/datadog-ecs-fargate"; 5 | -------------------------------------------------------------------------------- /src/ecs/utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import { Tags } from "aws-cdk-lib"; 10 | import * as ecs from "aws-cdk-lib/aws-ecs"; 11 | import * as iam from "aws-cdk-lib/aws-iam"; 12 | import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; 13 | import { Construct } from "constructs"; 14 | import log from "loglevel"; 15 | import { DatadogECSBaseProps } from "./interfaces"; 16 | import * as versionJson from "../../version.json"; 17 | import { invalidSiteError, siteList, TagKeys } from "../constants"; 18 | 19 | /** 20 | * Verifies that the provided props are valid for the Datadog ECS construct. 21 | */ 22 | export function validateECSBaseProps(props: DatadogECSBaseProps): void { 23 | if (process.env.DD_CDK_BYPASS_VALIDATION) { 24 | log.debug("Bypassing props validation..."); 25 | return; 26 | } 27 | 28 | // Valid site URL 29 | if ( 30 | props.site !== undefined && 31 | !siteList.includes(props.site.toLowerCase()) && 32 | !(props.site.startsWith("${Token[") && props.site.endsWith("]}")) 33 | ) { 34 | throw new Error(invalidSiteError); 35 | } 36 | 37 | // Agent feature configurations must all be defined 38 | if (props.dogstatsd === undefined) { 39 | throw new Error("The `dogstatsd` property must be defined."); 40 | } 41 | if (props.apm === undefined) { 42 | throw new Error("The `apm` property must be defined."); 43 | } 44 | 45 | // Agent container configuration validation 46 | if (props.registry === undefined) { 47 | throw new Error("The `registry` property must be defined."); 48 | } 49 | if (props.imageVersion === undefined) { 50 | throw new Error("The `version` property must be defined."); 51 | } 52 | 53 | // Health check validation 54 | if (props.isDatadogDependencyEnabled && props.datadogHealthCheck === undefined) { 55 | throw new Error("The `datadogHealthCheck` property must be defined when `isDatadogDependencyEnabled` is true."); 56 | } 57 | if (props.isDatadogDependencyEnabled && props.datadogHealthCheck!.command === undefined) { 58 | throw new Error("The `command` property must be defined in `datadogHealthCheck`."); 59 | } 60 | } 61 | 62 | export function isOperatingSystemLinux(props: ecs.FargateTaskDefinitionProps | undefined): boolean { 63 | if (props === undefined) { 64 | return true; 65 | } 66 | 67 | if (props.runtimePlatform === undefined) { 68 | return true; 69 | } 70 | 71 | if (props.runtimePlatform.operatingSystemFamily === undefined) { 72 | return true; 73 | } 74 | 75 | return props.runtimePlatform.operatingSystemFamily.isLinux(); 76 | } 77 | 78 | export function configureEcsPolicies(task: ecs.TaskDefinition) { 79 | task.addToTaskRolePolicy( 80 | new iam.PolicyStatement({ 81 | actions: ["ecs:ListClusters", "ecs:ListContainerInstances", "ecs:DescribeContainerInstances"], 82 | resources: ["*"], 83 | }), 84 | ); 85 | } 86 | 87 | export function getSecretApiKey(scope: Construct, props: DatadogECSBaseProps): ecs.Secret | undefined { 88 | if (props.apiKeySecret) { 89 | return ecs.Secret.fromSecretsManager(props.apiKeySecret); 90 | } else if (props.apiKeySecretArn) { 91 | const secret = secretsmanager.Secret.fromSecretCompleteArn(scope, "DatadogSecret", props.apiKeySecretArn); 92 | return ecs.Secret.fromSecretsManager(secret); 93 | } else { 94 | return undefined; 95 | } 96 | } 97 | 98 | export function addCdkConstructVersionTag(task: ecs.TaskDefinition): void { 99 | log.debug(`Adding CDK Construct version tag: ${versionJson.version}`); 100 | Tags.of(task).add(TagKeys.CDK, `v${versionJson.version}`, { 101 | includeResourceTypes: ["AWS::ECS::TaskDefinition"], 102 | }); 103 | } 104 | -------------------------------------------------------------------------------- /src/forwarder.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as crypto from "crypto"; 10 | import { Names } from "aws-cdk-lib"; 11 | import * as lambda from "aws-cdk-lib/aws-lambda"; 12 | import { FilterPattern, ILogGroup } from "aws-cdk-lib/aws-logs"; 13 | import { LambdaDestination } from "aws-cdk-lib/aws-logs-destinations"; 14 | import * as sfn from "aws-cdk-lib/aws-stepfunctions"; 15 | import { Construct } from "constructs"; 16 | import log from "loglevel"; 17 | import { SUBSCRIPTION_FILTER_PREFIX } from "./index"; 18 | 19 | function getForwarder(scope: Construct, forwarderArn: string) { 20 | const forwarderConstructId = generateForwarderConstructId(forwarderArn); 21 | if (scope.node.tryFindChild(forwarderConstructId)) { 22 | return scope.node.tryFindChild(forwarderConstructId) as lambda.IFunction; 23 | } else { 24 | return lambda.Function.fromFunctionArn(scope, forwarderConstructId, forwarderArn); 25 | } 26 | } 27 | 28 | export function addForwarder( 29 | scope: Construct, 30 | lam: lambda.Function, 31 | forwarderArn: string, 32 | createForwarderPermissions: boolean, 33 | ): void { 34 | const forwarder = getForwarder(scope, forwarderArn); 35 | const forwarderDestination = new LambdaDestination(forwarder, { addPermissions: createForwarderPermissions }); 36 | const subscriptionFilterName = generateSubscriptionFilterName(Names.uniqueId(lam), forwarderArn); 37 | log.debug(`Adding log subscription ${subscriptionFilterName} for ${lam.functionName}`); 38 | lam.logGroup.addSubscriptionFilter(subscriptionFilterName, { 39 | destination: forwarderDestination, 40 | filterPattern: FilterPattern.allEvents(), 41 | }); 42 | } 43 | 44 | export function addForwarderForStateMachine( 45 | scope: Construct, 46 | stateMachine: sfn.StateMachine, 47 | forwarderArn: string, 48 | logGroup: ILogGroup, 49 | ): void { 50 | const forwarder = getForwarder(scope, forwarderArn); 51 | const forwarderDestination = new LambdaDestination(forwarder); 52 | const subscriptionFilterName = generateSubscriptionFilterName(Names.uniqueId(stateMachine), forwarderArn); 53 | log.debug(`Adding log subscription ${subscriptionFilterName} for ${stateMachine.node.path}`); 54 | logGroup.addSubscriptionFilter(subscriptionFilterName, { 55 | destination: forwarderDestination, 56 | filterPattern: FilterPattern.allEvents(), 57 | }); 58 | } 59 | 60 | export function addForwarderToLogGroups( 61 | scope: Construct, 62 | logGroups: ILogGroup[], 63 | forwarderArn: string, 64 | createForwarderPermissions: boolean, 65 | ): void { 66 | const forwarder = getForwarder(scope, forwarderArn); 67 | const forwarderDestination = new LambdaDestination(forwarder, { addPermissions: createForwarderPermissions }); 68 | logGroups.forEach((group) => { 69 | const subscriptionFilterName = generateSubscriptionFilterName(Names.nodeUniqueId(group.node), forwarderArn); 70 | group.addSubscriptionFilter(subscriptionFilterName, { 71 | destination: forwarderDestination, 72 | filterPattern: FilterPattern.allEvents(), 73 | }); 74 | }); 75 | } 76 | 77 | export function generateForwarderConstructId(forwarderArn: string): string { 78 | log.debug("Generating construct Id for Datadog Lambda Forwarder"); 79 | return "forwarder" + crypto.createHash("sha256").update(forwarderArn).digest("hex"); 80 | } 81 | 82 | export function generateSubscriptionFilterName(functionUniqueId: string, forwarderArn: string): string { 83 | const subscriptionFilterValue: string = crypto 84 | .createHash("sha256") 85 | .update(functionUniqueId) 86 | .update(forwarderArn) 87 | .digest("hex"); 88 | const subscriptionFilterValueLength = subscriptionFilterValue.length; 89 | const subscriptionFilterName = 90 | SUBSCRIPTION_FILTER_PREFIX + 91 | subscriptionFilterValue.substring(subscriptionFilterValueLength - 8, subscriptionFilterValueLength); 92 | 93 | return subscriptionFilterName; 94 | } 95 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | export * from "./datadog-lambda"; 10 | export * from "./datadog-step-functions"; 11 | export * from "./layer"; 12 | export * from "./redirect"; 13 | export * from "./forwarder"; 14 | export * from "./env"; 15 | export * from "./transport"; 16 | export * from "./constants"; 17 | export * from "./interfaces"; 18 | export * from "./redirect"; 19 | export * from "./transport"; 20 | 21 | export * from "./ecs"; 22 | 23 | export * from "./apigateway"; 24 | -------------------------------------------------------------------------------- /src/interfaces.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import * as secrets from "aws-cdk-lib/aws-secretsmanager"; 11 | 12 | export interface DatadogLambdaProps { 13 | readonly dotnetLayerVersion?: number; 14 | readonly dotnetLayerArn?: string; 15 | readonly pythonLayerVersion?: number; 16 | readonly pythonLayerArn?: string; 17 | readonly nodeLayerVersion?: number; 18 | readonly nodeLayerArn?: string; 19 | readonly javaLayerVersion?: number; 20 | readonly javaLayerArn?: string; 21 | readonly rubyLayerVersion?: number; 22 | readonly rubyLayerArn?: string; 23 | readonly extensionLayerVersion?: number; 24 | readonly extensionLayerArn?: string; 25 | readonly addLayers?: boolean; 26 | readonly forwarderArn?: string; 27 | readonly flushMetricsToLogs?: boolean; 28 | readonly site?: string; 29 | readonly apiKey?: string; 30 | readonly apiKeySecretArn?: string; 31 | readonly apiKeySecret?: secrets.ISecret; 32 | readonly apiKmsKey?: string; 33 | readonly enableDatadogTracing?: boolean; 34 | readonly enableDatadogASM?: boolean; 35 | readonly enableMergeXrayTraces?: boolean; 36 | readonly injectLogContext?: boolean; 37 | readonly logLevel?: string; 38 | readonly enableDatadogLogs?: boolean; 39 | readonly captureLambdaPayload?: boolean; 40 | readonly captureCloudServicePayload?: boolean; 41 | readonly env?: string; 42 | readonly service?: string; 43 | readonly version?: string; 44 | readonly tags?: string; 45 | readonly createForwarderPermissions?: boolean; 46 | readonly sourceCodeIntegration?: boolean; 47 | readonly enableColdStartTracing?: boolean; 48 | readonly minColdStartTraceDuration?: number; 49 | readonly coldStartTraceSkipLibs?: string; 50 | readonly enableProfiling?: boolean; 51 | readonly encodeAuthorizerContext?: boolean; 52 | readonly decodeAuthorizerContext?: boolean; 53 | readonly apmFlushDeadline?: string | number; 54 | readonly redirectHandler?: boolean; 55 | readonly grantSecretReadAccess?: boolean; 56 | readonly useLayersFromAccount?: string; 57 | } 58 | 59 | /* 60 | * Makes fields shared with DefaultDatadogLambdaProps (in constants file) required. 61 | */ 62 | export interface DatadogLambdaStrictProps { 63 | readonly addLayers: boolean; 64 | readonly enableDatadogLogs: boolean; 65 | readonly captureLambdaPayload: boolean; 66 | readonly captureCloudServicePayload: boolean; 67 | readonly injectLogContext: boolean; 68 | readonly enableDatadogTracing: boolean; 69 | readonly enableDatadogASM: boolean; 70 | readonly enableMergeXrayTraces: boolean; 71 | readonly grantSecretReadAccess: boolean; 72 | readonly pythonLayerVersion?: number; 73 | readonly pythonLayerArn?: string; 74 | readonly nodeLayerVersion?: number; 75 | readonly nodeLayerArn?: string; 76 | readonly javaLayerVersion?: number; 77 | readonly javaLayerArn?: string; 78 | readonly extensionLayerVersion?: number; 79 | readonly extensionLayerArn?: string; 80 | readonly forwarderArn?: string; 81 | readonly flushMetricsToLogs?: boolean; 82 | readonly site?: string; 83 | readonly apiKey?: string; 84 | readonly apiKeySecretArn?: string; 85 | readonly apiKeySecret?: secrets.ISecret; 86 | readonly apiKmsKey?: string; 87 | readonly logLevel?: string; 88 | readonly sourceCodeIntegration?: boolean; 89 | readonly redirectHandler?: boolean; 90 | } 91 | 92 | export interface Runtime { 93 | readonly name: string; 94 | } 95 | 96 | export interface Node { 97 | readonly defaultChild: any; 98 | } 99 | 100 | export type LambdaFunction = lambda.Function | lambda.SingletonFunction; 101 | 102 | export interface DatadogStepFunctionsProps { 103 | readonly env?: string; 104 | readonly service?: string; 105 | readonly version?: string; 106 | readonly forwarderArn?: string; 107 | readonly tags?: string; 108 | } 109 | -------------------------------------------------------------------------------- /src/redirect.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import log from "loglevel"; 11 | import { 12 | RuntimeType, 13 | runtimeLookup, 14 | DD_HANDLER_ENV_VAR, 15 | AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR, 16 | AWS_LAMBDA_EXEC_WRAPPER, 17 | JS_HANDLER_WITH_LAYERS, 18 | JS_HANDLER, 19 | PYTHON_HANDLER, 20 | } from "./constants"; 21 | 22 | /** 23 | * To avoid modifying code in the user's lambda handler, redirect the handler to a Datadog 24 | * handler that initializes the Lambda Layers and then calls the original handler. 25 | * 'DD_LAMBDA_HANDLER' is set to the original handler in the lambda's environment for the 26 | * replacement handler to find. 27 | * 28 | * Unchanged aside from parameter type 29 | */ 30 | export function redirectHandlers(lam: lambda.Function, addLayers: boolean): void { 31 | log.debug(`Wrapping Lambda function handlers with Datadog handler...`); 32 | 33 | const runtime: string = lam.runtime.name; 34 | const runtimeType: RuntimeType = runtimeLookup[runtime]; 35 | 36 | if (runtimeType === RuntimeType.JAVA || runtimeType === RuntimeType.DOTNET) { 37 | lam.addEnvironment(AWS_LAMBDA_EXEC_WRAPPER_ENV_VAR, AWS_LAMBDA_EXEC_WRAPPER); 38 | return; 39 | } 40 | 41 | const cfnFuntion = lam.node.defaultChild as lambda.CfnFunction; 42 | if (cfnFuntion === undefined) { 43 | log.debug("Unable to get Lambda Function handler"); 44 | return; 45 | } 46 | 47 | const originalHandler = cfnFuntion.handler as string; 48 | lam.addEnvironment(DD_HANDLER_ENV_VAR, originalHandler); 49 | 50 | const handler = getDDHandler(runtimeType, addLayers); 51 | if (handler === null) { 52 | log.debug("Unable to get Datadog handler"); 53 | return; 54 | } 55 | 56 | cfnFuntion.handler = handler; 57 | } 58 | 59 | function getDDHandler(runtimeType: RuntimeType, addLayers: boolean): string | null { 60 | if (runtimeType === undefined || runtimeType === RuntimeType.UNSUPPORTED) { 61 | log.debug("Unsupported/undefined Lambda runtime"); 62 | return null; 63 | } 64 | switch (runtimeType) { 65 | case RuntimeType.NODE: 66 | return addLayers ? JS_HANDLER_WITH_LAYERS : JS_HANDLER; 67 | case RuntimeType.PYTHON: 68 | return PYTHON_HANDLER; 69 | case RuntimeType.CUSTOM: 70 | case RuntimeType.JAVA: 71 | case RuntimeType.DOTNET: 72 | case RuntimeType.RUBY: 73 | default: 74 | return null; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/sample/lambda/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | // eslint-disable-next-line import/no-extraneous-dependencies 10 | import * as lambdaPython from "@aws-cdk/aws-lambda-python-alpha"; 11 | import { App, Environment, Stack, StackProps } from "aws-cdk-lib"; 12 | import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigateway"; 13 | import * as lambda from "aws-cdk-lib/aws-lambda"; 14 | import * as lambdaNodejs from "aws-cdk-lib/aws-lambda-nodejs"; 15 | import { LogGroup } from "aws-cdk-lib/aws-logs"; 16 | import { DatadogLambda } from "../../index"; 17 | 18 | export class ExampleStack extends Stack { 19 | constructor(scope: App, id: string, props?: StackProps) { 20 | super(scope, id, props); 21 | 22 | const lambdaFunction = new lambda.Function(this, "HelloHandler", { 23 | runtime: lambda.Runtime.NODEJS_20_X, 24 | code: lambda.Code.fromAsset("./src/sample/lambda/python"), 25 | handler: "lambdaFunction.handler", 26 | }); 27 | 28 | const lambdaNodejsFunction = new lambdaNodejs.NodejsFunction(this, "NodeJSHandler", { 29 | runtime: lambda.Runtime.NODEJS_20_X, 30 | entry: "./src/sample/lambda/nodejs/hello_node.js", 31 | handler: "handler", 32 | }); 33 | 34 | const lambdaPythonFunction = new lambdaPython.PythonFunction(this, "PythonHandler", { 35 | runtime: lambda.Runtime.PYTHON_3_12, 36 | entry: "./src/sample/lambda/python/", 37 | index: "hello_py.py", 38 | handler: "handler", 39 | }); 40 | 41 | // set up rest api and log group 42 | const restLogGroup = new LogGroup(this, "restLogGroup"); 43 | new LambdaRestApi(this, "rest-test", { 44 | handler: lambdaNodejsFunction, 45 | deployOptions: { 46 | accessLogDestination: new LogGroupLogDestination(restLogGroup), 47 | }, 48 | }); 49 | 50 | const lambdaFunction1 = new lambda.Function(this, "HelloHandler1", { 51 | runtime: lambda.Runtime.NODEJS_20_X, 52 | code: lambda.Code.fromAsset("./src/sample/lambda/python"), 53 | handler: "lambdaFunction.handler", 54 | }); 55 | 56 | const restLogGroup1 = new LogGroup(this, "restLogGroup1"); 57 | new LambdaRestApi(this, "rest-test1", { 58 | handler: lambdaFunction1, 59 | deployOptions: { 60 | accessLogDestination: new LogGroupLogDestination(restLogGroup1), 61 | }, 62 | }); 63 | 64 | const lambdaFunction2 = new lambda.Function(this, "HelloHandler2", { 65 | runtime: lambda.Runtime.PYTHON_3_12, 66 | code: lambda.Code.fromAsset("./src/sample/lambda/python"), 67 | handler: "hello_py.handler", 68 | tracing: lambda.Tracing.ACTIVE, 69 | }); 70 | 71 | const restLogGroup2 = new LogGroup(this, "restLogGroup2"); 72 | new LambdaRestApi(this, "rest-test2", { 73 | handler: lambdaPythonFunction, 74 | deployOptions: { 75 | accessLogDestination: new LogGroupLogDestination(restLogGroup2), 76 | }, 77 | }); 78 | 79 | const datadogLambda = new DatadogLambda(this, "Datadog", { 80 | nodeLayerVersion: 62, 81 | pythonLayerVersion: 46, 82 | extensionLayerVersion: 10, 83 | // forwarderArn: "", 84 | // createForwarderPermissions: false, 85 | enableDatadogTracing: true, 86 | flushMetricsToLogs: true, 87 | apiKey: process.env.API_KEY, 88 | site: "datadoghq.com", 89 | }); 90 | datadogLambda.addLambdaFunctions([ 91 | lambdaFunction, 92 | lambdaNodejsFunction, 93 | lambdaPythonFunction, 94 | lambdaFunction1, 95 | lambdaFunction2, 96 | ]); 97 | datadogLambda.addForwarderToNonLambdaLogGroups([restLogGroup, restLogGroup1, restLogGroup2]); 98 | } 99 | } 100 | 101 | const app = new App(); 102 | const env: Environment = { 103 | account: process.env.CDK_DEFAULT_ACCOUNT || process.env.AWS_ACCOUNT_ID, 104 | region: process.env.CDK_DEFAULT_REGION || process.env.AWS_REGION, 105 | }; 106 | const stack = new ExampleStack(app, "ExampleDatadogStack", { env: env }); 107 | console.log("Stack name: " + stack.stackName); 108 | app.synth(); 109 | -------------------------------------------------------------------------------- /src/sample/lambda/index_cdk_v2_test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import { App, Stack, StackProps } from "aws-cdk-lib"; 10 | import * as lambda from "aws-cdk-lib/aws-lambda"; 11 | import * as lambdaNodejs from "aws-cdk-lib/aws-lambda-nodejs"; 12 | import { DatadogLambda } from "../../index"; 13 | 14 | export class ExampleStack extends Stack { 15 | constructor(scope: App, id: string, props?: StackProps) { 16 | super(scope, id, props); 17 | 18 | const lambdaNodejsFunction = new lambdaNodejs.NodejsFunction(this, "NodeJSHandler", { 19 | runtime: lambda.Runtime.NODEJS_20_X, 20 | entry: "./src/sample/lambda/nodejs/hello_node.js", 21 | handler: "handler", 22 | }); 23 | 24 | const datadogLambda = new DatadogLambda(this, "Datadog", { 25 | nodeLayerVersion: 67, 26 | extensionLayerVersion: 16, 27 | enableDatadogTracing: true, 28 | flushMetricsToLogs: true, 29 | apiKey: process.env.API_KEY, 30 | }); 31 | datadogLambda.addLambdaFunctions([lambdaNodejsFunction]); 32 | } 33 | } 34 | 35 | const app = new App(); 36 | const env = { account: process.env.CDK_DEFAULT_ACCOUNT, region: "sa-east-1" }; 37 | const stack = new ExampleStack(app, "CDKV2TestingExampleDatadogStack", { 38 | env: env, 39 | }); 40 | console.log("Stack name: " + stack.stackName); 41 | app.synth(); 42 | -------------------------------------------------------------------------------- /src/sample/lambda/python/hello_py.py: -------------------------------------------------------------------------------- 1 | # Unless explicitly stated otherwise all files in this repository are licensed 2 | # under the Apache License Version 2.0. 3 | # This product includes software developed at Datadog (https://www.datadoghq.com/). 4 | # Copyright 2021 Datadog, Inc. 5 | 6 | import json 7 | 8 | 9 | def handler(event, context): 10 | # print('request: {}'.format(json.dumps(event))) 11 | return { 12 | 'statusCode': 200, 13 | 'headers': { 14 | 'Content-Type': 'text/plain' 15 | }, 16 | 'body': 'Hello, CDK! You have hit ' 17 | } 18 | -------------------------------------------------------------------------------- /src/span-link.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Builds a payload for a Step Function LambdaInvoke task, so the Step Function traces 3 | * can be merged with downstream Lambda traces. 4 | * 5 | * This function modifies the provided payload to include context fields necessary 6 | * for trace merging purposes. If the payload already contains any of these fields, 7 | * an error is thrown to avoid conflicts. 8 | * 9 | * @param payload - The user's payload object. Defaults to an empty object. 10 | * @returns The modified payload object with necessary context added. 11 | * @throws {ConflictError} If the payload already contains `Execution`, `State`, or `StateMachine` fields. 12 | */ 13 | export function buildStepFunctionLambdaTaskPayloadToMergeTraces(payload: { [key: string]: any } = {}): { 14 | [key: string]: any; 15 | } { 16 | if ( 17 | "Execution" in payload || 18 | "Execution.$" in payload || 19 | "State" in payload || 20 | "State.$" in payload || 21 | "StateMachine" in payload || 22 | "StateMachine.$" in payload 23 | ) { 24 | throw new Error(`The LambdaInvoke task may be using custom Execution, State or StateMachine field. \ 25 | Step Functions Context Object injection skipped. Your Step Functions trace will not be merged with downstream Lambda traces. \ 26 | Please open an issue in https://github.com/DataDog/datadog-cdk-constructs to discuss your workaround.`); 27 | } 28 | 29 | payload["Execution.$"] = "$$.Execution"; 30 | payload["State.$"] = "$$.State"; 31 | payload["StateMachine.$"] = "$$.StateMachine"; 32 | return payload; 33 | } 34 | 35 | /** 36 | * Builds an input for a Step Function execution task, so the Step Function traces 37 | * can be merged with downstream Step Function traces. 38 | * 39 | * This function modifies the provided input to include context fields necessary 40 | * for trace merging purposes. If the input already contains CONTEXT or CONTEXT.$ field, 41 | * an error is thrown to avoid conflicts. 42 | * 43 | * @param input - The user's input object. Defaults to an empty object. 44 | * @returns The modified input object with necessary context added. 45 | * @throws {ConflictError} If the input already contains `CONTEXT` or `CONTEXT.$` fields. 46 | */ 47 | 48 | export function buildStepFunctionSfnExecutionTaskInputToMergeTraces(input: { [key: string]: any } = {}): { 49 | [key: string]: any; 50 | } { 51 | if ("CONTEXT" in input || "CONTEXT.$" in input) { 52 | throw new Error(`The StepFunction StartExecution task may be using custom CONTEXT field. Step Functions Context Object injection skipped. \ 53 | Your Step Functions trace will not be merged with downstream Lambda traces. \ 54 | Please open an issue in https://github.com/DataDog/datadog-cdk-constructs to discuss your workaround.`); 55 | } 56 | 57 | input["CONTEXT.$"] = `$$['Execution', 'State', 'StateMachine']`; 58 | return input; 59 | } 60 | -------------------------------------------------------------------------------- /src/tag.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import { Tags } from "aws-cdk-lib"; 10 | import * as lambda from "aws-cdk-lib/aws-lambda"; 11 | import * as sfn from "aws-cdk-lib/aws-stepfunctions"; 12 | import log from "loglevel"; 13 | import { TagKeys, DatadogLambdaProps, DatadogStepFunctionsProps } from "./index"; 14 | 15 | const versionJson = require("../version.json"); 16 | 17 | export function setTags( 18 | resource: lambda.Function | sfn.StateMachine, 19 | props: DatadogLambdaProps | DatadogStepFunctionsProps, 20 | ): void { 21 | log.debug(`Adding datadog tags`); 22 | if (props.env) { 23 | Tags.of(resource).add(TagKeys.ENV, props.env); 24 | } 25 | if (props.service) { 26 | Tags.of(resource).add(TagKeys.SERVICE, props.service); 27 | } 28 | if (props.version) { 29 | Tags.of(resource).add(TagKeys.VERSION, props.version); 30 | } 31 | if (props.tags) { 32 | const tagsArray = props.tags.split(","); 33 | tagsArray.forEach((tag: string) => { 34 | const [key, value] = tag.split(":"); 35 | if (key && value) { 36 | Tags.of(resource).add(key, value); 37 | } 38 | }); 39 | } 40 | 41 | if (resource instanceof sfn.StateMachine) { 42 | setStepFunctionTags(resource); 43 | } 44 | } 45 | 46 | function setStepFunctionTags(stateMachine: sfn.StateMachine) { 47 | Tags.of(stateMachine).add(TagKeys.DD_TRACE_ENABLED, "true"); 48 | Tags.of(stateMachine).add(TagKeys.CDK, `v${versionJson.version}`); 49 | } 50 | -------------------------------------------------------------------------------- /src/transport.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Unless explicitly stated otherwise all files in this repository are licensed 3 | * under the Apache License Version 2.0. 4 | * 5 | * This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | * Copyright 2021 Datadog, Inc. 7 | */ 8 | 9 | import * as lambda from "aws-cdk-lib/aws-lambda"; 10 | import log from "loglevel"; 11 | import { runtimeLookup, RuntimeType } from "./index"; 12 | 13 | export const API_KEY_ENV_VAR = "DD_API_KEY"; 14 | export const API_KEY_SECRET_ARN_ENV_VAR = "DD_API_KEY_SECRET_ARN"; 15 | export const KMS_API_KEY_ENV_VAR = "DD_KMS_API_KEY"; 16 | export const SITE_URL_ENV_VAR = "DD_SITE"; 17 | export const FLUSH_METRICS_TO_LOGS_ENV_VAR = "DD_FLUSH_TO_LOG"; 18 | 19 | export const transportDefaults = { 20 | site: "datadoghq.com", 21 | flushMetricsToLogs: true, 22 | enableDatadogTracing: true, 23 | }; 24 | 25 | export class Transport { 26 | flushMetricsToLogs: boolean; 27 | site: string; 28 | apiKey?: string; 29 | apiKeySecretArn?: string; 30 | apiKmsKey?: string; 31 | extensionLayerVersion?: number; 32 | extensionLayerArn?: string; 33 | 34 | constructor( 35 | flushMetricsToLogs?: boolean, 36 | site?: string, 37 | apiKey?: string, 38 | apiKeySecretArn?: string, 39 | apiKmsKey?: string, 40 | extensionLayerVersion?: number, 41 | extensionLayerArn?: string, 42 | ) { 43 | if (flushMetricsToLogs === undefined) { 44 | log.debug(`No value provided for flushMetricsToLogs, defaulting to ${transportDefaults.flushMetricsToLogs}`); 45 | this.flushMetricsToLogs = transportDefaults.flushMetricsToLogs; 46 | } else { 47 | this.flushMetricsToLogs = flushMetricsToLogs; 48 | } 49 | 50 | this.extensionLayerVersion = extensionLayerVersion; 51 | this.extensionLayerArn = extensionLayerArn; 52 | // If the extension is used, metrics will be submitted via the extension. 53 | if (this.extensionLayerVersion !== undefined || this.extensionLayerArn !== undefined) { 54 | const extensionInfo = 55 | this.extensionLayerArn !== undefined 56 | ? `ARN ${this.extensionLayerArn}` 57 | : `version ${this.extensionLayerVersion}`; 58 | log.debug(`Using extension ${extensionInfo}, metrics will be submitted via the extension`); 59 | this.flushMetricsToLogs = false; 60 | } 61 | 62 | if (site === undefined) { 63 | log.debug(`No value provided for site, defaulting to ${transportDefaults.site}`); 64 | this.site = transportDefaults.site; 65 | } else { 66 | this.site = site; 67 | } 68 | 69 | this.apiKey = apiKey; 70 | this.apiKeySecretArn = apiKeySecretArn; 71 | this.apiKmsKey = apiKmsKey; 72 | } 73 | 74 | applyEnvVars(lam: lambda.Function) { 75 | log.debug(`Setting Datadog transport environment variables...`); 76 | lam.addEnvironment(FLUSH_METRICS_TO_LOGS_ENV_VAR, this.flushMetricsToLogs.toString()); 77 | if (this.site !== undefined && this.flushMetricsToLogs === false) { 78 | lam.addEnvironment(SITE_URL_ENV_VAR, this.site); 79 | } 80 | if (this.apiKey !== undefined) { 81 | lam.addEnvironment(API_KEY_ENV_VAR, this.apiKey); 82 | } 83 | if (this.apiKeySecretArn !== undefined) { 84 | const isNode = runtimeLookup[lam.runtime.name] === RuntimeType.NODE; 85 | const isSendingSynchronousMetrics = 86 | this.extensionLayerVersion === undefined && this.extensionLayerArn === undefined && !this.flushMetricsToLogs; 87 | if (isSendingSynchronousMetrics && isNode) { 88 | throw new Error( 89 | `\`apiKeySecretArn\` is not supported for Node runtimes when using Synchronous Metrics. Use either \`apiKey\` or \`apiKmsKey\`.`, 90 | ); 91 | } 92 | lam.addEnvironment(API_KEY_SECRET_ARN_ENV_VAR, this.apiKeySecretArn); 93 | } 94 | if (this.apiKmsKey !== undefined) { 95 | lam.addEnvironment(KMS_API_KEY_ENV_VAR, this.apiKmsKey); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /test/assets/Dockerfile: -------------------------------------------------------------------------------- 1 | # Only used for tests 2 | 3 | FROM public.ecr.aws/lambda/nodejs:16-x86_64 4 | -------------------------------------------------------------------------------- /test/datadog-step-functions.spec.ts: -------------------------------------------------------------------------------- 1 | import { Stack, Token } from "aws-cdk-lib"; 2 | import * as logs from "aws-cdk-lib/aws-logs"; 3 | import * as sfn from "aws-cdk-lib/aws-stepfunctions"; 4 | import { DatadogStepFunctions, buildLogGroupName } from "../src/datadog-step-functions"; 5 | 6 | describe("DatadogStepFunctions", () => { 7 | describe("setUpLogging", () => { 8 | it("sets up log config if it's not set", () => { 9 | const stack = new Stack(); 10 | const stateMachine = new sfn.StateMachine(stack, "StateMachine", { 11 | definitionBody: sfn.DefinitionBody.fromChainable(new sfn.Pass(stack, "PassState")), 12 | }); 13 | 14 | const datadogSfn = new DatadogStepFunctions(stack, "DatadogStepFunctions", {}); 15 | datadogSfn.addStateMachines([stateMachine]); 16 | 17 | const cfnStateMachine = stateMachine.node.defaultChild as sfn.CfnStateMachine; 18 | const logConfig = cfnStateMachine.loggingConfiguration as sfn.CfnStateMachine.LoggingConfigurationProperty; 19 | expect(logConfig.level).toBe("ALL"); 20 | expect(logConfig.includeExecutionData).toBe(true); 21 | expect(logConfig.destinations).toHaveLength(1); 22 | }); 23 | 24 | it("sets log level to ALL and includeExecutionData to true if they are not", () => { 25 | const stack = new Stack(); 26 | const stateMachine = new sfn.StateMachine(stack, "StateMachine", { 27 | definitionBody: sfn.DefinitionBody.fromChainable(new sfn.Pass(stack, "PassState")), 28 | logs: { 29 | destination: new logs.LogGroup(stack, "LogGroup"), 30 | level: sfn.LogLevel.ERROR, 31 | includeExecutionData: false, 32 | }, 33 | }); 34 | 35 | const datadogSfn = new DatadogStepFunctions(stack, "DatadogStepFunctions", {}); 36 | datadogSfn.addStateMachines([stateMachine]); 37 | 38 | const cfnStateMachine = stateMachine.node.defaultChild as sfn.CfnStateMachine; 39 | const logConfig = cfnStateMachine.loggingConfiguration as sfn.CfnStateMachine.LoggingConfigurationProperty; 40 | expect(logConfig.level).toBe("ALL"); 41 | expect(logConfig.includeExecutionData).toBe(true); 42 | expect(logConfig.destinations).toHaveLength(1); 43 | }); 44 | 45 | it("throws if loggingConfiguration is an unresolved token", () => { 46 | const stack = new Stack(); 47 | const stateMachine = new sfn.StateMachine(stack, "StateMachine", { 48 | definitionBody: sfn.DefinitionBody.fromChainable(new sfn.Pass(stack, "PassState")), 49 | }); 50 | 51 | const cfnStateMachine = stateMachine.node.defaultChild as sfn.CfnStateMachine; 52 | cfnStateMachine.loggingConfiguration = Token.asAny({}); 53 | 54 | const datadogSfn = new DatadogStepFunctions(stack, "DatadogStepFunctions", {}); 55 | expect(() => datadogSfn.addStateMachines([stateMachine])).toThrowError( 56 | "loggingConfiguration is an an unresolved token. Step Function Instrumentation is not supported. Please open a feature request in https://github.com/DataDog/datadog-cdk-constructs.", 57 | ); 58 | }); 59 | }); 60 | }); 61 | 62 | describe("buildLogGroupName", () => { 63 | test("builds log group name with env", () => { 64 | const stateMachine = { 65 | node: { 66 | path: "MyStack/MyStateMachine", 67 | }, 68 | } as sfn.StateMachine; 69 | const logGroupName = buildLogGroupName(stateMachine, "dev"); 70 | expect(logGroupName).toBe("/aws/vendedlogs/states/MyStack-MyStateMachine-Logs-dev"); 71 | }); 72 | 73 | test("builds log group name without env", () => { 74 | const stateMachine = { 75 | node: { 76 | path: "MyStack/MyStateMachine", 77 | }, 78 | } as sfn.StateMachine; 79 | const logGroupName = buildLogGroupName(stateMachine, undefined); 80 | expect(logGroupName).toBe("/aws/vendedlogs/states/MyStack-MyStateMachine-Logs"); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /test/ecs/environment.spec.ts: -------------------------------------------------------------------------------- 1 | import { EnvVarManager } from "../../src/ecs/environment"; 2 | 3 | describe("EnvVarManager", () => { 4 | let envVarManager: EnvVarManager; 5 | 6 | beforeEach(() => { 7 | envVarManager = new EnvVarManager(); 8 | }); 9 | 10 | it("should add an environment variable", () => { 11 | envVarManager.add("KEY1", "value1"); 12 | expect(envVarManager.retrieve("KEY1")).toBe("value1"); 13 | }); 14 | 15 | it("should not add an environment variable if the value is undefined", () => { 16 | envVarManager.add("KEY1", undefined); 17 | expect(envVarManager.retrieve("KEY1")).toBeUndefined(); 18 | }); 19 | 20 | it("should overwrite an existing environment variable and record the key", () => { 21 | envVarManager.add("KEY1", "value1"); 22 | envVarManager.add("KEY1", "value2"); 23 | expect(envVarManager.retrieve("KEY1")).toBe("value2"); 24 | expect(envVarManager.retrieveOverwrittenKeys()).toContain("KEY1"); 25 | }); 26 | 27 | it("should add all environment variables from a record", () => { 28 | const envVars = { KEY1: "value1", KEY2: "value2" }; 29 | envVarManager.addAll(envVars); 30 | expect(envVarManager.retrieve("KEY1")).toBe("value1"); 31 | expect(envVarManager.retrieve("KEY2")).toBe("value2"); 32 | }); 33 | 34 | it("should return all stored environment variables", () => { 35 | const envVars = { KEY1: "value1", KEY2: "value2" }; 36 | envVarManager.addAll(envVars); 37 | expect(envVarManager.retrieveAll()).toEqual(envVars); 38 | }); 39 | 40 | it("should return a list of keys that have been overwritten", () => { 41 | envVarManager.add("KEY1", "value1"); 42 | envVarManager.add("KEY1", "value2"); 43 | envVarManager.add("KEY2", "value3"); 44 | envVarManager.add("KEY2", "value4"); 45 | expect(envVarManager.retrieveOverwrittenKeys()).toEqual(["KEY1", "KEY2"]); 46 | }); 47 | 48 | it("should return a string representation of the environment variables", () => { 49 | const envVars = { KEY1: "value1", KEY2: "value2" }; 50 | envVarManager.addAll(envVars); 51 | expect(envVarManager.toString()).toBe(JSON.stringify(envVars)); 52 | }); 53 | 54 | it("should initialize with default environment variables", () => { 55 | const defaultEnvVars = { KEY1: "value1", KEY2: "value2" }; 56 | envVarManager = new EnvVarManager(defaultEnvVars); 57 | expect(envVarManager.retrieveAll()).toEqual(defaultEnvVars); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /test/ecs/fargate/cws.spec.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Template, Match } from "aws-cdk-lib/assertions"; 3 | import * as ecs from "aws-cdk-lib/aws-ecs"; 4 | import { Construct } from "constructs"; 5 | import * as ecsDatadog from "../../../src/ecs"; 6 | import { EntryPointPrefixCWS } from "../../../src/ecs/fargate/constants"; 7 | 8 | describe("DatadogECSFargateTaskDefinition", () => { 9 | let app: cdk.App; 10 | let stack: cdk.Stack; 11 | let scope: Construct; 12 | let id: string; 13 | let props: ecs.FargateTaskDefinitionProps; 14 | let datadogProps: ecsDatadog.DatadogECSFargateProps; 15 | 16 | beforeEach(() => { 17 | app = new cdk.App(); 18 | stack = new cdk.Stack(app, "TestStack"); 19 | 20 | scope = stack; // Use the stack as the construct scope 21 | id = "TestTaskDefinition"; 22 | props = { 23 | family: "test-family", 24 | cpu: 256, 25 | memoryLimitMiB: 512, 26 | }; 27 | datadogProps = { 28 | registry: "public.ecr.aws/datadog/agent", 29 | imageVersion: "latest", 30 | apiKey: "test-api-key", 31 | isDatadogDependencyEnabled: true, 32 | cws: { 33 | isEnabled: true, 34 | }, 35 | }; 36 | }); 37 | 38 | it("creates the CWS container when enabled", () => { 39 | const task = new ecsDatadog.DatadogECSFargateTaskDefinition(scope, id, props, datadogProps); 40 | const template = Template.fromStack(stack); 41 | 42 | expect(task.cwsContainer).toBeDefined(); 43 | 44 | // Validate that the CWS container is created 45 | template.hasResourceProperties("AWS::ECS::TaskDefinition", { 46 | ContainerDefinitions: Match.arrayWith([ 47 | Match.objectLike({ 48 | Name: "cws-instrumentation-init", 49 | Image: "datadog/cws-instrumentation:latest", 50 | }), 51 | ]), 52 | }); 53 | }); 54 | 55 | it("should inject the CWS entry point prefix and add the volume mount", () => { 56 | const entryPoint = ["/app/start.sh"]; 57 | const taskDefinition = new ecsDatadog.DatadogECSFargateTaskDefinition(scope, id, props, datadogProps); 58 | const containerProps: ecs.ContainerDefinitionOptions = { 59 | image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), 60 | memoryLimitMiB: 512, 61 | entryPoint: entryPoint, 62 | }; 63 | taskDefinition.addContainer("app-container", containerProps); 64 | 65 | // Expected entry point with CWS prefix 66 | entryPoint.unshift(...EntryPointPrefixCWS); 67 | const template = Template.fromStack(stack); 68 | 69 | // Validate that the entry point prefix and volume mount are added 70 | template.hasResourceProperties("AWS::ECS::TaskDefinition", { 71 | ContainerDefinitions: Match.arrayWith([ 72 | Match.objectLike({ 73 | Name: "app-container", 74 | EntryPoint: Match.arrayWith(entryPoint), 75 | MountPoints: Match.arrayWith([ 76 | Match.objectLike({ 77 | ContainerPath: "/cws-instrumentation-volume", 78 | SourceVolume: "cws-instrumentation-volume", 79 | ReadOnly: false, 80 | }), 81 | ]), 82 | }), 83 | ]), 84 | }); 85 | }); 86 | 87 | it("applies CWS container configurations", () => { 88 | datadogProps = { 89 | ...datadogProps, 90 | cws: { 91 | isEnabled: true, 92 | cpu: 128, 93 | memoryLimitMiB: 256, 94 | }, 95 | }; 96 | 97 | const taskDefinition = new ecsDatadog.DatadogECSFargateTaskDefinition(scope, id, props, datadogProps); 98 | const template = Template.fromStack(stack); 99 | 100 | // Validate that the cpu and memory parameters are applied to the CWS container 101 | template.hasResourceProperties("AWS::ECS::TaskDefinition", { 102 | ContainerDefinitions: Match.arrayWith([ 103 | Match.objectLike({ 104 | Name: taskDefinition.cwsContainer!.containerName, 105 | Cpu: 128, 106 | Memory: 256, 107 | }), 108 | ]), 109 | }); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /test/ecs/fargate/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { LoggingType } from "../../../src/ecs/fargate/interfaces"; 2 | import { validateECSFargateProps } from "../../../src/ecs/fargate/utils"; 3 | 4 | describe("validateECSFargateProps", () => { 5 | // no-dd-sa:typescript-best-practices/no-explicit-any 6 | let props: any; 7 | 8 | beforeEach(() => { 9 | props = { 10 | logCollection: { 11 | isEnabled: true, 12 | loggingType: LoggingType.FLUENTBIT, 13 | fluentbitConfig: { 14 | logDriverConfig: { 15 | registry: "public.ecr.aws/aws-observability/aws-for-fluent-bit", 16 | imageVersion: "stable", 17 | }, 18 | firelensOptions: {}, 19 | }, 20 | }, 21 | cws: { 22 | isEnabled: false, 23 | }, 24 | isLinux: true, 25 | }; 26 | }); 27 | 28 | it("should not throw an error when all required fields are valid", () => { 29 | expect(() => validateECSFargateProps(props)).not.toThrow(); 30 | }); 31 | 32 | it("should throw an error if logCollection is undefined", () => { 33 | delete props.logCollection; 34 | expect(() => validateECSFargateProps(props)).toThrow(); 35 | }); 36 | 37 | it("should throw an error if loggingType is undefined when logging is enabled", () => { 38 | delete props.logCollection.loggingType; 39 | expect(() => validateECSFargateProps(props)).toThrow(); 40 | }); 41 | 42 | it("should throw an error if logDriverConfig is undefined when logging is enabled", () => { 43 | delete props.logCollection.fluentbitConfig.logDriverConfig; 44 | expect(() => validateECSFargateProps(props)).toThrow(); 45 | }); 46 | 47 | it("should throw an error if logDriverConfig is undefined when logging is enabled", () => { 48 | delete props.logCollection.fluentbitConfig.firelensOptions; 49 | expect(() => validateECSFargateProps(props)).toThrow(); 50 | }); 51 | 52 | it("should throw an error if Fluent Bit logging is enabled but the operating system is not Linux", () => { 53 | props.isLinux = false; 54 | expect(() => validateECSFargateProps(props)).toThrow(); 55 | }); 56 | 57 | it("should not throw an error if logging is disabled", () => { 58 | props.logCollection.isEnabled = false; 59 | delete props.logCollection.loggingType; 60 | delete props.logCollection.fluentbitConfig.logDriverConfig; 61 | expect(() => validateECSFargateProps(props)).not.toThrow(); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/lambda/example-lambda.py: -------------------------------------------------------------------------------- 1 | def handler(event, context): 2 | return {} -------------------------------------------------------------------------------- /test/lambda/example-lambda.ts: -------------------------------------------------------------------------------- 1 | export const handler = (): void => { 2 | return; 3 | }; 4 | -------------------------------------------------------------------------------- /test/span-link.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | buildStepFunctionLambdaTaskPayloadToMergeTraces, 3 | buildStepFunctionSfnExecutionTaskInputToMergeTraces, 4 | } from "../src/span-link"; 5 | 6 | describe("buildStepFunctionLambdaTaskPayloadToMergeTraces", () => { 7 | it("adds necessary fields to an empty payload", () => { 8 | const result = buildStepFunctionLambdaTaskPayloadToMergeTraces(); 9 | expect(result).toEqual({ 10 | "Execution.$": "$$.Execution", 11 | "State.$": "$$.State", 12 | "StateMachine.$": "$$.StateMachine", 13 | }); 14 | }); 15 | 16 | it("adds necessary fields to a non-empty payload", () => { 17 | const payload = { "custom-key": "custom-value" }; 18 | const result = buildStepFunctionLambdaTaskPayloadToMergeTraces(payload); 19 | expect(result).toEqual({ 20 | "custom-key": "custom-value", 21 | "Execution.$": "$$.Execution", 22 | "State.$": "$$.State", 23 | "StateMachine.$": "$$.StateMachine", 24 | }); 25 | }); 26 | 27 | it("throws an error if payload already contains Execution field", () => { 28 | const payload = { Execution: "value" }; 29 | expect(() => buildStepFunctionLambdaTaskPayloadToMergeTraces(payload)).toThrowError( 30 | "The LambdaInvoke task may be using custom Execution, State or StateMachine field. Step Functions Context Object injection skipped. Your Step Functions trace will not be merged with downstream Lambda traces. Please open an issue in https://github.com/DataDog/datadog-cdk-constructs to discuss your workaround.", 31 | ); 32 | }); 33 | }); 34 | 35 | describe("buildStepFunctionSfnExecutionTaskInputToMergeTraces", () => { 36 | it("adds necessary fields to an empty input", () => { 37 | const result = buildStepFunctionSfnExecutionTaskInputToMergeTraces(); 38 | expect(result).toEqual({ 39 | "CONTEXT.$": `$$['Execution', 'State', 'StateMachine']`, 40 | }); 41 | }); 42 | 43 | it("adds necessary fields to a non-empty input", () => { 44 | const input = { "custom-key": "custom-value" }; 45 | const result = buildStepFunctionSfnExecutionTaskInputToMergeTraces(input); 46 | expect(result).toEqual({ 47 | "custom-key": "custom-value", 48 | "CONTEXT.$": `$$['Execution', 'State', 'StateMachine']`, 49 | }); 50 | }); 51 | 52 | it("throws an error if input already contains CONTEXT field", () => { 53 | const input = { CONTEXT: "value" }; 54 | expect(() => buildStepFunctionSfnExecutionTaskInputToMergeTraces(input)).toThrowError( 55 | "The StepFunction StartExecution task may be using custom CONTEXT field. Step Functions Context Object injection skipped. Your Step Functions trace will not be merged with downstream Lambda traces. Please open an issue in https://github.com/DataDog/datadog-cdk-constructs to discuss your workaround.", 56 | ); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/test-utils.ts: -------------------------------------------------------------------------------- 1 | import * as lambda from "aws-cdk-lib/aws-lambda"; 2 | import { CfnSubscriptionFilter } from "aws-cdk-lib/aws-logs"; 3 | import { Construct } from "constructs"; 4 | import { SUBSCRIPTION_FILTER_PREFIX } from "../src/index"; 5 | 6 | export const findDatadogSubscriptionFilters = (baseConstruct: Construct) => { 7 | // extract lambdaFunction property from Singleton Function 8 | // using bracket notation here since lambdaFunction is a private property 9 | const baseConstructModified: Construct = isSingletonFunction(baseConstruct) 10 | ? baseConstruct["lambdaFunction"] // eslint-disable-line dot-notation 11 | : baseConstruct; 12 | 13 | return baseConstructModified.node 14 | .findAll() 15 | .filter((construct) => construct.node.id.startsWith(SUBSCRIPTION_FILTER_PREFIX)) 16 | .map((construct) => { 17 | const cfnSubscriptionFilters = construct.node.children.filter( 18 | (child) => child instanceof CfnSubscriptionFilter, 19 | ) as CfnSubscriptionFilter[]; 20 | 21 | return cfnSubscriptionFilters.map((cfnSubcriptionFilter) => { 22 | return { 23 | id: construct.node.id, 24 | destinationArn: cfnSubcriptionFilter.destinationArn, 25 | }; 26 | }); 27 | }) 28 | .reduce((acc, subscriptionFilters) => acc.concat(subscriptionFilters), []); 29 | }; 30 | 31 | function isSingletonFunction(fn: Construct): fn is lambda.SingletonFunction { 32 | return fn.hasOwnProperty("lambdaFunction"); 33 | } 34 | -------------------------------------------------------------------------------- /tsconfig.dev.json: -------------------------------------------------------------------------------- 1 | // ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". 2 | { 3 | "compilerOptions": { 4 | "alwaysStrict": true, 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "experimentalDecorators": true, 8 | "inlineSourceMap": true, 9 | "inlineSources": true, 10 | "lib": [ 11 | "es2020" 12 | ], 13 | "module": "CommonJS", 14 | "noEmitOnError": false, 15 | "noFallthroughCasesInSwitch": true, 16 | "noImplicitAny": true, 17 | "noImplicitReturns": true, 18 | "noImplicitThis": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "resolveJsonModule": true, 22 | "strict": true, 23 | "strictNullChecks": true, 24 | "strictPropertyInitialization": true, 25 | "stripInternal": true, 26 | "target": "ES2020" 27 | }, 28 | "include": [ 29 | "src/**/*.ts", 30 | "test/**/*.ts", 31 | ".projenrc.js" 32 | ], 33 | "exclude": [ 34 | "node_modules" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "alwaysStrict": true, 4 | "declaration": true, 5 | "experimentalDecorators": true, 6 | "inlineSourceMap": true, 7 | "inlineSources": true, 8 | "lib": [ 9 | "es2018" 10 | ], 11 | "module": "CommonJS", 12 | "noEmitOnError": false, 13 | "noFallthroughCasesInSwitch": true, 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noImplicitThis": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "resolveJsonModule": true, 20 | "strict": true, 21 | "strictNullChecks": true, 22 | "strictPropertyInitialization": true, 23 | "stripInternal": true, 24 | "target": "ES2018" 25 | }, 26 | "include": [ 27 | ".projenrc.js", 28 | "src/**/*.ts", 29 | "test/**/*.ts" 30 | ], 31 | "exclude": [ 32 | "node_modules" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /tsconfig.jest.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "alwaysStrict": true, 4 | "declaration": true, 5 | "experimentalDecorators": true, 6 | "inlineSourceMap": true, 7 | "inlineSources": true, 8 | "lib": [ 9 | "es2018" 10 | ], 11 | "module": "CommonJS", 12 | "noEmitOnError": false, 13 | "noFallthroughCasesInSwitch": true, 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noImplicitThis": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "resolveJsonModule": true, 20 | "strict": true, 21 | "strictNullChecks": true, 22 | "strictPropertyInitialization": true, 23 | "stripInternal": true, 24 | "target": "ES2018" 25 | }, 26 | "include": [ 27 | ".projenrc.js", 28 | "src/**/*.ts", 29 | "test/**/*.ts" 30 | ], 31 | "exclude": [ 32 | "node_modules" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.6.0" 3 | } 4 | --------------------------------------------------------------------------------