├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml ├── lychee.toml ├── release.yml └── workflows │ ├── check-links.yaml │ ├── ci-collector.yml │ ├── ci-java.yml │ ├── ci-nodejs.yml │ ├── ci-python.yml │ ├── ci-shellcheck.yml │ ├── ci-terraform.yml │ ├── close-stale.yaml │ ├── codeql.yml │ ├── fossa.yml │ ├── layer-publish.yml │ ├── ossf-scorecard.yml │ ├── publish-layer-collector.yml │ ├── release-layer-collector.yml │ ├── release-layer-java.yml │ ├── release-layer-nodejs.yml │ ├── release-layer-python.yml │ └── release-layer-ruby.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── RELEASE.md ├── collector ├── Makefile ├── Makefile.Common ├── README.md ├── config.yaml ├── go.mod ├── go.sum ├── internal │ ├── collector │ │ └── collector.go │ ├── confmap │ │ └── converter │ │ │ ├── decoupleafterbatchconverter │ │ │ ├── README.md │ │ │ ├── converter.go │ │ │ └── converter_test.go │ │ │ └── disablequeuedretryconverter │ │ │ ├── converter.go │ │ │ └── converter_test.go │ ├── extensionapi │ │ └── client.go │ ├── lifecycle │ │ ├── manager.go │ │ └── manager_test.go │ ├── telemetryapi │ │ ├── client.go │ │ ├── listener.go │ │ └── types.go │ └── tools │ │ ├── Makefile │ │ ├── go.mod │ │ ├── go.sum │ │ └── tools.go ├── lambdacomponents │ ├── Makefile │ ├── connector │ │ ├── pkg.go │ │ └── spanmetrics.go │ ├── custom.go │ ├── default.go │ ├── exporter │ │ ├── debug.go │ │ ├── otlp.go │ │ ├── otlphttp.go │ │ ├── pkg.go │ │ └── prometheusremotewrite.go │ ├── extension │ │ ├── basicauth.go │ │ ├── pkg.go │ │ └── sigv4auth.go │ ├── go.mod │ ├── go.sum │ ├── processor │ │ ├── attributes.go │ │ ├── batch.go │ │ ├── coldstart.go │ │ ├── decouple.go │ │ ├── filter.go │ │ ├── memorylimiter.go │ │ ├── pkg.go │ │ ├── probabilisticsampler.go │ │ ├── resource.go │ │ └── span.go │ └── receiver │ │ ├── otlp.go │ │ ├── pkg.go │ │ └── telemetryapi.go ├── lambdalifecycle │ ├── Makefile │ ├── go.mod │ └── notifier.go ├── main.go ├── processor │ ├── coldstartprocessor │ │ ├── Makefile │ │ ├── README.md │ │ ├── config.go │ │ ├── config_test.go │ │ ├── doc.go │ │ ├── factory.go │ │ ├── factory_test.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── processor.go │ │ └── processor_test.go │ └── decoupleprocessor │ │ ├── Makefile │ │ ├── README.md │ │ ├── config.go │ │ ├── config_test.go │ │ ├── doc.go │ │ ├── factory.go │ │ ├── factory_test.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── processor.go │ │ ├── processor_test.go │ │ └── testdata │ │ └── config.yaml └── receiver │ └── telemetryapireceiver │ ├── Makefile │ ├── README.md │ ├── config.go │ ├── config_test.go │ ├── doc.go │ ├── factory.go │ ├── factory_test.go │ ├── go.mod │ ├── go.sum │ ├── internal │ └── sharedcomponent │ │ ├── sharedcomponent.go │ │ └── sharedcomponent_test.go │ ├── receiver.go │ ├── receiver_test.go │ ├── testdata │ └── config.yaml │ └── types.go ├── docs └── design_proposal.md ├── dotnet ├── README.md └── sample-apps │ └── aws-sdk │ ├── deploy │ └── wrapper │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ └── wrapper │ └── SampleApps │ ├── AwsSdkSample.sln │ ├── AwsSdkSample │ ├── AwsSdkSample.csproj │ ├── Function.cs │ └── Properties │ │ └── launchSettings.json │ └── build.sh ├── go ├── README.md └── sample-apps │ ├── aws-sdk │ └── deploy │ │ └── wrapper │ │ ├── main.tf │ │ ├── outputs.tf │ │ └── variables.tf │ └── function │ ├── build.sh │ ├── function.go │ ├── go.mod │ └── go.sum ├── java ├── README.md ├── awssdk-autoconfigure │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── io │ │ │ └── opentelemetry │ │ │ └── instrumentation │ │ │ └── awssdk │ │ │ └── v2_2 │ │ │ └── autoconfigure │ │ │ └── AutoconfiguredTracingExecutionInterceptor.java │ │ └── resources │ │ └── software │ │ └── amazon │ │ └── awssdk │ │ └── global │ │ └── handlers │ │ └── execution.interceptors ├── build.gradle.kts ├── dependencyManagement │ └── build.gradle.kts ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── layer-javaagent │ ├── build.gradle.kts │ └── scripts │ │ └── otel-handler ├── layer-wrapper │ ├── build.gradle.kts │ └── scripts │ │ ├── otel-handler │ │ ├── otel-proxy-handler │ │ ├── otel-sqs-handler │ │ └── otel-stream-handler ├── sample-apps │ ├── aws-sdk │ │ ├── README.md │ │ ├── build.gradle.kts │ │ ├── deploy │ │ │ ├── agent │ │ │ │ ├── main.tf │ │ │ │ ├── outputs.tf │ │ │ │ └── variables.tf │ │ │ └── wrapper │ │ │ │ ├── main.tf │ │ │ │ ├── outputs.tf │ │ │ │ └── variables.tf │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── io │ │ │ │ └── opentelemetry │ │ │ │ └── lambda │ │ │ │ └── sampleapps │ │ │ │ └── awssdk │ │ │ │ └── AwsSdkRequestHandler.java │ │ │ └── resources │ │ │ └── log4j2.xml │ ├── okhttp │ │ ├── README.md │ │ ├── build.gradle.kts │ │ ├── deploy │ │ │ └── wrapper │ │ │ │ ├── main.tf │ │ │ │ ├── outputs.tf │ │ │ │ └── variables.tf │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── io │ │ │ │ └── opentelemetry │ │ │ │ └── lambda │ │ │ │ └── sampleapps │ │ │ │ └── okhttp │ │ │ │ └── OkHttpRequestHandler.java │ │ │ └── resources │ │ │ └── log4j2.xml │ └── sqs │ │ ├── README.md │ │ ├── build.gradle.kts │ │ ├── deploy │ │ ├── agent │ │ │ ├── main.tf │ │ │ ├── outputs.tf │ │ │ └── variables.tf │ │ └── wrapper │ │ │ ├── main.tf │ │ │ ├── outputs.tf │ │ │ └── variables.tf │ │ └── src │ │ └── main │ │ ├── java │ │ └── io │ │ │ └── opentelemetry │ │ │ └── lambda │ │ │ └── sampleapps │ │ │ └── sqs │ │ │ └── SqsRequestHandler.java │ │ └── resources │ │ └── log4j2.xml └── settings.gradle.kts ├── nodejs ├── .commitlintrc.yml ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .npmignore ├── README.md ├── eslint.config.js ├── lerna.json ├── package-lock.json ├── package.json ├── packages │ └── layer │ │ ├── .eslintignore │ │ ├── .eslintrc.js │ │ ├── .mocharc.json │ │ ├── install-externals.sh │ │ ├── package.json │ │ ├── scripts │ │ └── otel-handler │ │ ├── src │ │ ├── init.mjs │ │ ├── loader.mjs │ │ └── wrapper.ts │ │ ├── test │ │ ├── handler.spec.mjs │ │ ├── handler.spec.ts │ │ ├── handler │ │ │ ├── cjs │ │ │ │ ├── index.js │ │ │ │ ├── index_commonjs.cjs │ │ │ │ └── package.json │ │ │ └── esm │ │ │ │ ├── index.js │ │ │ │ ├── index_esm.mjs │ │ │ │ └── package.json │ │ └── wrapper.spec.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.webpack.json │ │ └── webpack.config.js ├── sample-apps │ └── aws-sdk │ │ ├── .eslintignore │ │ ├── .eslintrc.js │ │ ├── README.md │ │ ├── deploy │ │ └── wrapper │ │ │ ├── main.tf │ │ │ ├── outputs.tf │ │ │ └── variables.tf │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ └── index.ts │ │ └── tsconfig.json ├── tsconfig.base.json └── tsconfig.esm.json ├── python ├── README.md ├── sample-apps │ ├── aws-sdk │ │ └── deploy │ │ │ └── wrapper │ │ │ ├── main.tf │ │ │ ├── outputs.tf │ │ │ └── variables.tf │ ├── build.sh │ ├── function │ │ ├── lambda_function.py │ │ └── requirements.txt │ ├── run.sh │ └── template.yml └── src │ ├── build.sh │ ├── otel │ ├── Dockerfile │ ├── Makefile │ ├── otel_sdk │ │ ├── nodeps-requirements.txt │ │ ├── otel-instrument │ │ ├── otel_wrapper.py │ │ └── requirements.txt │ └── tests │ │ ├── mocks │ │ └── lambda_function.py │ │ ├── nodeps-requirements.txt │ │ ├── requirements.txt │ │ └── test_otel.py │ ├── run.sh │ ├── template.yml │ └── tox.ini ├── ruby ├── README.md ├── sample-apps │ ├── function │ │ ├── Gemfile │ │ └── lambda_function.rb │ └── template.yml └── src │ ├── build.sh │ ├── otel │ ├── Dockerfile │ └── layer │ │ ├── Gemfile │ │ ├── Makefile │ │ ├── otel-handler │ │ └── wrapper.rb │ ├── template.yml │ └── zip_ruby_layer.sh └── utils ├── aws-cloudformation └── aws-cf-stack-for-layer-publish.yml ├── sam └── run.sh └── terraform └── api-gateway-proxy ├── main.tf ├── outputs.tf └── variables.tf /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 2 | 3 | * @open-telemetry/lambda-extension-approvers 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Steps to reproduce** 14 | If possible, provide a recipe for reproducing the error. 15 | 16 | **What did you expect to see?** 17 | A clear and concise description of what you expected to see. 18 | 19 | **What did you see instead?** 20 | A clear and concise description of what you saw instead. 21 | 22 | **What version of collector/language SDK version did you use?** 23 | Version: (e.g., `v0.58.0`, `v1.11.0`, etc) 24 | 25 | **What language layer did you use?** 26 | Config: (e.g., `Java`, `Python`, etc) 27 | 28 | **Additional context** 29 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "github-actions" 6 | directories: 7 | - "/" 8 | schedule: 9 | interval: "weekly" 10 | groups: 11 | actions: 12 | patterns: 13 | - "*" 14 | 15 | - package-ecosystem: "gomod" 16 | directories: 17 | - "/collector" 18 | - "/collector/internal/tools" 19 | - "/collector/lambdacomponents" 20 | - "/collector/lambdalifecycle" 21 | - "/collector/processor/coldstartprocessor" 22 | - "/collector/processor/decoupleprocessor" 23 | - "/collector/receiver/telemetryapireceiver" 24 | - "/go/sample-apps/function" 25 | schedule: 26 | interval: "weekly" 27 | groups: 28 | opentelemetry-deps-collector: 29 | patterns: 30 | - "*opentelemetry*" 31 | collector-other: 32 | patterns: 33 | - "*" 34 | 35 | - package-ecosystem: "gradle" 36 | directories: 37 | - "/java" 38 | schedule: 39 | interval: "weekly" 40 | groups: 41 | opentelemetry-deps-java: 42 | patterns: 43 | - "io.opentelemetry.*" 44 | java-other: 45 | patterns: 46 | - "*" 47 | 48 | - package-ecosystem: "npm" 49 | directories: 50 | - "/nodejs" 51 | - "/nodejs/packages/layer" 52 | - "/nodejs/sample-apps/aws-sdk" 53 | schedule: 54 | interval: "weekly" 55 | groups: 56 | opentelemetry-deps-nodejs: 57 | patterns: 58 | - "@opentelemetry/*" 59 | nodejs-other: 60 | patterns: 61 | - "*" 62 | 63 | - package-ecosystem: "pip" 64 | directories: 65 | - "/python/src/otel" 66 | - "/python/sample-apps/function" 67 | - "/python/src/otel/otel_sdk" 68 | - "/python/src/otel/tests" 69 | schedule: 70 | interval: "weekly" 71 | groups: 72 | opentelemetry-deps-python: 73 | patterns: 74 | - "opentelemetry-*" 75 | python-other: 76 | patterns: 77 | - "*" 78 | 79 | - package-ecosystem: "bundler" 80 | directories: 81 | - "/ruby/src/otel/layer" 82 | - "/ruby/sample-apps/function" 83 | schedule: 84 | interval: "weekly" 85 | groups: 86 | opentelemetry-deps-ruby: 87 | patterns: 88 | - "opentelemetry-*" 89 | ruby-other: 90 | patterns: 91 | - "*" 92 | -------------------------------------------------------------------------------- /.github/lychee.toml: -------------------------------------------------------------------------------- 1 | include-fragments = true 2 | 3 | accept = ["200..=299", "429"] 4 | 5 | exclude = [ 6 | "^http(s)?://localhost", 7 | "^http(s)?://example.com", 8 | "https://docs.aws.amazon.com", 9 | "https://console.aws.amazon.com" 10 | ] 11 | 12 | # better to be safe and avoid failures 13 | max-retries = 6 14 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes 2 | 3 | changelog: 4 | categories: 5 | 6 | - title: Collector 7 | labels: 8 | - go 9 | 10 | - title: Python 11 | labels: 12 | - python 13 | 14 | - title: Javascript 15 | labels: 16 | - javascript 17 | 18 | - title: Java 19 | labels: 20 | - java 21 | 22 | - title: Ruby 23 | labels: 24 | - ruby 25 | 26 | - title: Other Dependencies 27 | labels: 28 | - dependencies 29 | 30 | - title: Other 31 | labels: 32 | - '*' 33 | -------------------------------------------------------------------------------- /.github/workflows/check-links.yaml: -------------------------------------------------------------------------------- 1 | name: check-links 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.ref_name }} 9 | cancel-in-progress: true 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | changedfiles: 15 | name: changed files 16 | runs-on: ubuntu-latest 17 | env: 18 | PR_HEAD: ${{ github.event.pull_request.head.sha }} 19 | outputs: 20 | files: ${{ steps.changes.outputs.files }} 21 | steps: 22 | - name: Checkout Repo 23 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 24 | with: 25 | fetch-depth: 0 26 | - name: Get changed files 27 | id: changes 28 | run: | 29 | files=$(git diff --name-only --diff-filter=ACMRTUXB $(git merge-base origin/main $PR_HEAD) $PR_HEAD | grep .md$ | xargs) 30 | 31 | if [ -z "$files" ] && git diff --name-only $(git merge-base origin/main $PR_HEAD) $PR_HEAD | grep -q "package.json"; then 32 | files="**/*.md" 33 | fi 34 | 35 | echo "files=$files" >> $GITHUB_OUTPUT 36 | check-links: 37 | runs-on: ubuntu-latest 38 | needs: changedfiles 39 | if: ${{needs.changedfiles.outputs.files}} 40 | steps: 41 | - name: Checkout Repo 42 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 43 | with: 44 | fetch-depth: 0 45 | 46 | - name: Link Checker 47 | id: lychee 48 | uses: lycheeverse/lychee-action@1d97d84f0bc547f7b25f4c2170d87d810dc2fb2c 49 | with: 50 | args: "--verbose --no-progress ${{needs.changedfiles.outputs.files}} --config .github/lychee.toml" 51 | failIfEmpty: false 52 | -------------------------------------------------------------------------------- /.github/workflows/ci-collector.yml: -------------------------------------------------------------------------------- 1 | name: "Continuous Build (Collector)" 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'collector/**' 7 | - '.github/workflows/ci-collector.yml' 8 | branches: 9 | - main 10 | pull_request: 11 | paths: 12 | - 'collector/**' 13 | - '.github/workflows/ci-collector.yml' 14 | branches: 15 | - main 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | test: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 26 | with: 27 | go-version-file: collector/go.mod 28 | - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 29 | with: 30 | path: ~/go/pkg/mod 31 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 32 | restore-keys: | 33 | ${{ runner.os }}-go- 34 | - name: Tidy 35 | run: make gotidy 36 | working-directory: collector 37 | - name: Run tests 38 | run: make gotest 39 | working-directory: collector 40 | build: 41 | runs-on: ubuntu-latest 42 | needs: [test] 43 | strategy: 44 | matrix: 45 | architecture: [ amd64, arm64 ] 46 | steps: 47 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 48 | - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 49 | with: 50 | go-version-file: collector/go.mod 51 | - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 52 | with: 53 | path: ~/go/pkg/mod 54 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 55 | restore-keys: | 56 | ${{ runner.os }}-go- 57 | - name: Build Collector Executable for ${{ matrix.architecture }} architecture 58 | run: GOARCH=${{ matrix.architecture }} make package 59 | working-directory: collector 60 | - name: Get Lambda Layer amd64 architecture value 61 | if: ${{ matrix.architecture == 'amd64' }} 62 | run: echo LAMBDA_LAYER_ARCHITECTURE=x86 | tee --append $GITHUB_ENV 63 | - name: Get Lambda Layer arm64 architecture value 64 | if: ${{ matrix.architecture == 'arm64' }} 65 | run: echo LAMBDA_LAYER_ARCHITECTURE=ARM | tee --append $GITHUB_ENV 66 | - name: Confirm architecture of built collector 67 | working-directory: collector/build/extensions 68 | run: | 69 | grep ${{ env.LAMBDA_LAYER_ARCHITECTURE }} <<< "$(file collector)" 70 | -------------------------------------------------------------------------------- /.github/workflows/ci-java.yml: -------------------------------------------------------------------------------- 1 | name: "Continuous Build (Java)" 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'java/**' 7 | - '.github/workflows/ci-java.yml' 8 | branches: 9 | - main 10 | pull_request: 11 | paths: 12 | - 'java/**' 13 | - '.github/workflows/ci-java.yml' 14 | branches: 15 | - main 16 | 17 | permissions: 18 | pull-requests: write 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | 26 | - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 27 | with: 28 | distribution: corretto 29 | java-version: 17 30 | 31 | - name: Setup Gradle 32 | uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 33 | with: 34 | add-job-summary-as-pr-comment: on-failure # Valid values are 'never' (default), 'always', and 'on-failure' 35 | 36 | - name: Execute Gradle build 37 | run: | 38 | cd java 39 | ./gradlew build --scan --stacktrace 40 | -------------------------------------------------------------------------------- /.github/workflows/ci-nodejs.yml: -------------------------------------------------------------------------------- 1 | name: "Continuous Build (NodeJS)" 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'nodejs/**' 7 | - '.github/workflows/ci-nodejs.yml' 8 | branches: 9 | - main 10 | pull_request: 11 | paths: 12 | - 'nodejs/**' 13 | - '.github/workflows/ci-nodejs.yml' 14 | branches: 15 | - main 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 26 | with: 27 | node-version: 18 28 | - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 29 | with: 30 | path: ~/.npm 31 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 32 | restore-keys: | 33 | ${{ runner.os }}-node- 34 | - run: npm install 35 | working-directory: nodejs 36 | - run: npm run lint 37 | working-directory: nodejs 38 | - run: npm test 39 | working-directory: nodejs 40 | -------------------------------------------------------------------------------- /.github/workflows/ci-python.yml: -------------------------------------------------------------------------------- 1 | name: "Continuous Build (Python)" 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'python/**' 7 | - '.github/workflows/ci-python.yml' 8 | branches: 9 | - main 10 | pull_request: 11 | paths: 12 | - 'python/**' 13 | - '.github/workflows/ci-python.yml' 14 | branches: 15 | - main 16 | 17 | env: 18 | AWS_REGION: us-east-1 19 | # Copied this CORE_REPO_SHA from 20 | # https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/.github/workflows/test.yml#L9 21 | CORE_REPO_SHA: v1.19.0 22 | 23 | permissions: 24 | contents: read 25 | 26 | jobs: 27 | build: 28 | runs-on: ubuntu-latest 29 | 30 | strategy: 31 | matrix: 32 | # If you add a python version here, please make sure that the collector/Makefile publish and publish-layer targets 33 | # get updated as well 34 | python: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] 35 | 36 | steps: 37 | - name: Checkout this repo 38 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 39 | - name: Setup Python for OTel Python SDK 40 | uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 41 | with: 42 | python-version: ${{ matrix.python }} 43 | - name: Install tox testing package 44 | working-directory: python/src 45 | run: | 46 | pip install tox 47 | tox 48 | - name: Set up Go for ADOT Collector 49 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 50 | with: 51 | go-version: '^1.20.8' 52 | - name: Build Python Layer which includes ADOT Collector 53 | working-directory: python/src 54 | run: ./run.sh -b 55 | -------------------------------------------------------------------------------- /.github/workflows/ci-shellcheck.yml: -------------------------------------------------------------------------------- 1 | name: "Continuous Build (shellcheck)" 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | shellcheck: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 13 | 14 | - name: Install shell check 15 | run: sudo apt update && sudo apt install --assume-yes shellcheck 16 | 17 | - name: Run shellcheck 18 | run: >- 19 | find . -type f | 20 | grep -v '.git' | 21 | xargs -n 30 file | 22 | grep -i shell | 23 | awk -F':' '{print $1}' | 24 | xargs shellcheck 25 | 26 | -------------------------------------------------------------------------------- /.github/workflows/ci-terraform.yml: -------------------------------------------------------------------------------- 1 | name: "Continuous Build (Terraform)" 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**/*.tf' 7 | - '.github/workflows/ci-terraform.yml' 8 | branches: 9 | - main 10 | pull_request: 11 | paths: 12 | - '**/*.tf' 13 | - '.github/workflows/ci-terraform.yml' 14 | branches: 15 | - main 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | check-terraform-syntax: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 26 | - run: terraform fmt -check -recursive 27 | -------------------------------------------------------------------------------- /.github/workflows/close-stale.yaml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: "40 3 * * *" # Run daily at 3:40 AM 5 | 6 | permissions: 7 | issues: write 8 | pull-requests: write 9 | 10 | jobs: 11 | stale: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 15 | with: 16 | repo-token: ${{ secrets.GITHUB_TOKEN }} 17 | stale-issue-message: 'This issue was marked stale. It will be closed in 30 days without additional activity.' 18 | close-issue-message: 'Closed as inactive. Feel free to reopen if this issue is still relevant.' 19 | 20 | stale-pr-message: 'This PR was marked stale. It will be closed in 30 days without additional activity.' 21 | close-pr-message: 'Closed as inactive. Feel free to reopen if this PR is still being worked on.' 22 | 23 | days-before-stale: 365 24 | days-before-close: 30 25 | 26 | operations-per-run: 500 27 | -------------------------------------------------------------------------------- /.github/workflows/fossa.yml: -------------------------------------------------------------------------------- 1 | name: FOSSA scanning 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | fossa: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | 17 | - uses: fossas/fossa-action@c0a7d013f84c8ee5e910593186598625513cc1e4 # v1.6.0 18 | with: 19 | api-key: ${{secrets.FOSSA_API_KEY}} 20 | team: OpenTelemetry 21 | -------------------------------------------------------------------------------- /.github/workflows/ossf-scorecard.yml: -------------------------------------------------------------------------------- 1 | name: OSSF Scorecard 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | schedule: 8 | - cron: "59 7 * * 6" # once a week 9 | workflow_dispatch: 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | analysis: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | # Needed for Code scanning upload 18 | security-events: write 19 | # Needed for GitHub OIDC token if publish_results is true 20 | id-token: write 21 | steps: 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | persist-credentials: false 25 | 26 | - uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 27 | with: 28 | results_file: results.sarif 29 | results_format: sarif 30 | publish_results: true 31 | 32 | # Upload the results as artifacts (optional). Commenting out will disable 33 | # uploads of run results in SARIF format to the repository Actions tab. 34 | # https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts 35 | - name: "Upload artifact" 36 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 37 | with: 38 | name: SARIF file 39 | path: results.sarif 40 | retention-days: 5 41 | 42 | # Upload the results to GitHub's code scanning dashboard (optional). 43 | # Commenting out will disable upload of results to your repo's Code Scanning dashboard 44 | - name: "Upload to code-scanning" 45 | uses: github/codeql-action/upload-sarif@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 46 | with: 47 | sarif_file: results.sarif 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | extension.zip 3 | 4 | build 5 | .gradle 6 | .idea 7 | 8 | .terraform* 9 | terraform.* 10 | 11 | .vscode/ 12 | 13 | .DS_Store 14 | 15 | .tox 16 | __pycache__/* 17 | .pyc 18 | build.toml 19 | 20 | *.zip 21 | 22 | collector/VERSION 23 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Lambda Layer Release Procedure 2 | 3 | The release process is almost entirely managed by [GitHub actions](https://github.com/open-telemetry/opentelemetry-lambda/tree/main/.github/workflows). To publish a new layer: 4 | 5 | 1. Create a new tag for the layer to publish. For example, to create a new collector layer, the following command is used: 6 | `git tag layer-collector/0.0.8` 7 | 2. Push the tag to [opentelemetry-lambda](https://github.com/open-telemetry/opentelemetry-lambda) repository to trigger the publish action: 8 | `git push origin tag layer-collector/0.0.8` 9 | 3. Wait for the [release workflow](https://github.com/open-telemetry/opentelemetry-lambda/actions/workflows/release-layer-collector.yml) to finish. 10 | 4. Create a release in https://github.com/open-telemetry/opentelemetry-lambda/releases/new 11 | * Select a the newly pushed tag 12 | * Select the corresponding previous release 13 | * Click "Generate Release Notes" 14 | * Adjust the release notes. Include the ARN, list of changes and diff with previous label. 15 | -------------------------------------------------------------------------------- /collector/Makefile.Common: -------------------------------------------------------------------------------- 1 | GOTEST_OPT?= -race -timeout 120s 2 | GOCMD?= go 3 | GOTEST=$(GOCMD) test 4 | GO_ACC=go-acc 5 | LINT=golangci-lint 6 | IMPI=impi 7 | 8 | GOOS := $(shell $(GOCMD) env GOOS) 9 | GOARCH := $(shell $(GOCMD) env GOARCH) 10 | GH := $(shell which gh) 11 | 12 | .PHONY: test 13 | test: 14 | $(GOTEST) $(GOTEST_OPT) ./... 15 | 16 | .PHONY: test-with-cover 17 | test-with-cover: 18 | $(GO_ACC) --output=coverage.out ./... 19 | 20 | .PHONY: benchmark 21 | benchmark: 22 | $(GOTEST) -bench=. -benchtime=5s -count 5 -benchmem -cpuprofile=cpu.out -memprofile=mem.out -run=notests ./ 23 | 24 | .PHONY: fmt 25 | fmt: 26 | gofmt -w -s ./ 27 | goimports -w -local github.com/open-telemetry/opentelemetry-lambda/collector ./ 28 | 29 | .PHONY: tidy 30 | tidy: 31 | rm -fr go.sum 32 | $(GOCMD) mod tidy -compat=1.21 33 | 34 | .PHONY: lint 35 | lint: 36 | $(LINT) run 37 | 38 | .PHONY: generate 39 | generate: 40 | $(GOCMD) generate ./... 41 | 42 | .PHONY: impi 43 | impi: 44 | @$(IMPI) --local github.com/open-telemetry/opentelemetry-lambda/collector --scheme stdThirdPartyLocal ./... 45 | 46 | .PHONY: moddownload 47 | moddownload: 48 | $(GOCMD) mod download 49 | 50 | .PHONY: align 51 | align: 52 | -fieldalignment -fix . 53 | -------------------------------------------------------------------------------- /collector/config.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | grpc: 5 | endpoint: "localhost:4317" 6 | http: 7 | endpoint: "localhost:4318" 8 | 9 | exporters: 10 | debug: 11 | verbosity: detailed 12 | 13 | service: 14 | pipelines: 15 | traces: 16 | receivers: [otlp] 17 | exporters: [debug] 18 | metrics: 19 | receivers: [otlp] 20 | exporters: [debug] 21 | telemetry: 22 | metrics: 23 | address: localhost:8888 24 | -------------------------------------------------------------------------------- /collector/internal/confmap/converter/decoupleafterbatchconverter/README.md: -------------------------------------------------------------------------------- 1 | # DecoupleAfterBatch Converter 2 | 3 | The `DecoupleAfterBatch` converter automatically modifies the collector's configuration for the Lambda distribution. Its purpose is to ensure that a decouple processor is always present after a batch processor in a pipeline, in order to prevent potential data loss due to the Lambda environment being frozen. 4 | 5 | ## Behavior 6 | 7 | The converter scans the collector's configuration and makes the following adjustments: 8 | 9 | 1. If a pipeline contains a batch processor with no decouple processor defined after it, the converter will automatically add a decouple processor to the end of the pipeline. 10 | 11 | 2. If a pipeline contains a batch processor with a decouple processor already defined after it or there is no batch processor defined, the converter will not make any changes to the pipeline configuration. 12 | -------------------------------------------------------------------------------- /collector/internal/confmap/converter/disablequeuedretryconverter/converter.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package disablequeuedretryconverter // import "github.com/open-telemetry/opentelemetry-lambda/collector/internal/confmap/converter/disablequeuedretryconverter" 15 | 16 | import ( 17 | "context" 18 | "fmt" 19 | "strings" 20 | 21 | "go.opentelemetry.io/collector/confmap" 22 | ) 23 | 24 | const ( 25 | expKey = "exporters" 26 | ) 27 | 28 | var exporters = map[string]struct{}{ 29 | "awskinesis": {}, 30 | "coralogix": {}, 31 | "datadog": {}, 32 | "dynatrace": {}, 33 | "googlecloud": {}, 34 | "googlecloudpubsub": {}, 35 | "googlemanagedprometheus": {}, 36 | "humio": {}, 37 | "influxdb": {}, 38 | "jaeger": {}, 39 | "kafka": {}, 40 | "logzio": {}, 41 | "loki": {}, 42 | "mezmo": {}, 43 | "observiq": {}, 44 | "opencensus": {}, 45 | "otlp": {}, 46 | "otlphttp": {}, 47 | "pulsar": {}, 48 | "sapm": {}, 49 | "signalfx": {}, 50 | "skywalking": {}, 51 | "splunkhec": {}, 52 | "sumologic": {}, 53 | "tanzuobservability": {}, 54 | "zipkin": {}, 55 | } 56 | 57 | type converter struct { 58 | } 59 | 60 | // New returns a confmap.Converter, that ensures queued retry is disabled for all configured exporters. 61 | func New() confmap.Converter { 62 | return &converter{} 63 | } 64 | 65 | func (c converter) Convert(_ context.Context, conf *confmap.Conf) error { 66 | out := make(map[string]interface{}) 67 | expVal := conf.Get(expKey) 68 | 69 | switch exps := expVal.(type) { 70 | case map[string]interface{}: 71 | for name := range exps { 72 | if _, ok := exporters[strings.Split(name, "/")[0]]; !ok { 73 | continue 74 | } 75 | out[fmt.Sprintf("%s::%s::sending_queue::enabled", expKey, name)] = false 76 | } 77 | } 78 | if err := conf.Merge(confmap.NewFromStringMap(out)); err != nil { 79 | return err 80 | } 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /collector/internal/confmap/converter/disablequeuedretryconverter/converter_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package disablequeuedretryconverter 16 | 17 | import ( 18 | "context" 19 | "testing" 20 | 21 | "github.com/stretchr/testify/assert" 22 | "go.opentelemetry.io/collector/confmap" 23 | ) 24 | 25 | func TestConvert(t *testing.T) { 26 | for _, tc := range []struct { 27 | name string 28 | conf *confmap.Conf 29 | expected *confmap.Conf 30 | err error 31 | }{ 32 | { 33 | name: "no exporters", 34 | conf: confmap.New(), 35 | expected: confmap.New(), 36 | err: nil, 37 | }, 38 | { 39 | name: "no queuing exporters", 40 | conf: confmap.NewFromStringMap(map[string]any{"exporters": map[string]any{"prometheus": map[string]any{}}}), 41 | expected: confmap.NewFromStringMap(map[string]any{"exporters": map[string]any{"prometheus": map[string]any{}}}), 42 | err: nil, 43 | }, 44 | { 45 | name: "some queuing exporters", 46 | conf: confmap.NewFromStringMap(map[string]any{"exporters": map[string]any{"prometheus": map[string]any{}, "otlp": map[string]any{}}}), 47 | expected: confmap.NewFromStringMap(map[string]any{"exporters": map[string]any{"prometheus": map[string]any{}, "otlp": map[string]any{"sending_queue": map[string]any{"enabled": false}}}}), 48 | err: nil, 49 | }, 50 | { 51 | name: "many queuing exporters", 52 | conf: confmap.NewFromStringMap(map[string]any{"exporters": map[string]any{"otlphttp": map[string]any{}, "otlp": map[string]any{}}}), 53 | expected: confmap.NewFromStringMap(map[string]any{"exporters": map[string]any{"otlphttp": map[string]any{"sending_queue": map[string]any{"enabled": false}}, "otlp": map[string]any{"sending_queue": map[string]any{"enabled": false}}}}), 54 | err: nil, 55 | }, 56 | } { 57 | t.Run(tc.name, func(t *testing.T) { 58 | c := New() 59 | err := c.Convert(context.Background(), tc.conf) 60 | assert.Equal(t, err, tc.err) 61 | assert.Equal(t, tc.conf, tc.expected) 62 | }) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /collector/internal/tools/Makefile: -------------------------------------------------------------------------------- 1 | include ../../Makefile.Common 2 | -------------------------------------------------------------------------------- /collector/internal/tools/tools.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //go:build tools 16 | // +build tools 17 | 18 | package tools // import "go.opentelemetry.io/otel/internal/tools" 19 | 20 | import ( 21 | _ "github.com/client9/misspell/cmd/misspell" 22 | _ "github.com/golangci/golangci-lint/cmd/golangci-lint" 23 | _ "github.com/google/addlicense" 24 | _ "github.com/jcchavezs/porto/cmd/porto" 25 | _ "github.com/ory/go-acc" 26 | _ "github.com/pavius/impi/cmd/impi" 27 | _ "github.com/tcnksm/ghr" 28 | _ "github.com/wadey/gocovmerge" 29 | _ "go.opentelemetry.io/build-tools/chloggen" 30 | _ "go.opentelemetry.io/build-tools/crosslink" 31 | _ "go.opentelemetry.io/build-tools/multimod" 32 | _ "go.opentelemetry.io/build-tools/semconvgen" 33 | _ "golang.org/x/exp/cmd/apidiff" 34 | _ "golang.org/x/tools/cmd/goimports" 35 | ) 36 | -------------------------------------------------------------------------------- /collector/lambdacomponents/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.Common 2 | -------------------------------------------------------------------------------- /collector/lambdacomponents/connector/pkg.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package connector 16 | 17 | import "go.opentelemetry.io/collector/connector" 18 | 19 | var Factories []func(extensionId string) connector.Factory -------------------------------------------------------------------------------- /collector/lambdacomponents/connector/spanmetrics.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.connector.all || lambdacomponents.connector.spanmetrics) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package connector 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector" 21 | "go.opentelemetry.io/collector/connector" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) connector.Factory { 26 | return spanmetricsconnector.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/custom.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package lambdacomponents 18 | 19 | import ( 20 | custom_connector "github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponents/connector" 21 | custom_exporter "github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponents/exporter" 22 | custom_extension "github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponents/extension" 23 | custom_processor "github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponents/processor" 24 | custom_receiver "github.com/open-telemetry/opentelemetry-lambda/collector/lambdacomponents/receiver" 25 | 26 | "go.opentelemetry.io/collector/component" 27 | "go.opentelemetry.io/collector/otelcol" 28 | 29 | "go.uber.org/multierr" 30 | ) 31 | 32 | func Components(extensionID string) (otelcol.Factories, error) { 33 | var errs []error 34 | 35 | receivers, err := makeFactoryMap(custom_receiver.Factories, extensionID) 36 | if err != nil { 37 | errs = append(errs, err) 38 | } 39 | 40 | processors, err := makeFactoryMap(custom_processor.Factories, extensionID) 41 | if err != nil { 42 | errs = append(errs, err) 43 | } 44 | 45 | exporters, err := makeFactoryMap(custom_exporter.Factories, extensionID) 46 | if err != nil { 47 | errs = append(errs, err) 48 | } 49 | 50 | extensions, err := makeFactoryMap(custom_extension.Factories, extensionID) 51 | if err != nil { 52 | errs = append(errs, err) 53 | } 54 | 55 | connectors, err := makeFactoryMap(custom_connector.Factories, extensionID) 56 | if err != nil { 57 | errs = append(errs, err) 58 | } 59 | 60 | factories := otelcol.Factories{ 61 | Receivers: receivers, 62 | Processors: processors, 63 | Exporters: exporters, 64 | Extensions: extensions, 65 | Connectors: connectors, 66 | } 67 | 68 | return factories, multierr.Combine(errs...) 69 | } 70 | 71 | func makeFactoryMap[F component.Factory](factories []func(extensionId string) F, extensionId string) (map[component.Type]F, error) { 72 | preprocessedFactories := make([]F, len(factories)) 73 | for i, f := range factories { 74 | preprocessedFactories[i] = f(extensionId) 75 | } 76 | 77 | return otelcol.MakeFactoryMap(preprocessedFactories...) 78 | } 79 | -------------------------------------------------------------------------------- /collector/lambdacomponents/exporter/debug.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.exporter.all || lambdacomponents.exporter.debug) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package exporter 18 | 19 | import ( 20 | "go.opentelemetry.io/collector/exporter" 21 | "go.opentelemetry.io/collector/exporter/debugexporter" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) exporter.Factory { 26 | return debugexporter.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/exporter/otlp.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.exporter.all || lambdacomponents.exporter.otlp) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package exporter 18 | 19 | import ( 20 | "go.opentelemetry.io/collector/exporter" 21 | "go.opentelemetry.io/collector/exporter/otlpexporter" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) exporter.Factory { 26 | return otlpexporter.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/exporter/otlphttp.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.exporter.all || lambdacomponents.exporter.otlphttp) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package exporter 18 | 19 | import ( 20 | "go.opentelemetry.io/collector/exporter" 21 | "go.opentelemetry.io/collector/exporter/otlphttpexporter" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) exporter.Factory { 26 | return otlphttpexporter.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/exporter/pkg.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package exporter 16 | 17 | import "go.opentelemetry.io/collector/exporter" 18 | 19 | var Factories []func(extensionId string) exporter.Factory -------------------------------------------------------------------------------- /collector/lambdacomponents/exporter/prometheusremotewrite.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.exporter.all || lambdacomponents.exporter.prometheusremotewrite) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package exporter 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/prometheusremotewriteexporter" 21 | "go.opentelemetry.io/collector/exporter" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) exporter.Factory { 26 | return prometheusremotewriteexporter.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/extension/basicauth.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.extension.all || lambdacomponents.extension.basicauth) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package extension 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension" 21 | "go.opentelemetry.io/collector/extension" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) extension.Factory { 26 | return basicauthextension.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/extension/pkg.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package extension 16 | 17 | import "go.opentelemetry.io/collector/extension" 18 | 19 | var Factories []func(extensionId string) extension.Factory -------------------------------------------------------------------------------- /collector/lambdacomponents/extension/sigv4auth.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.extension.all || lambdacomponents.extension.sigv4auth) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package extension 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/extension/sigv4authextension" 21 | "go.opentelemetry.io/collector/extension" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) extension.Factory { 26 | return sigv4authextension.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/attributes.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.attributes) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor" 21 | "go.opentelemetry.io/collector/processor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return attributesprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/batch.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.batch) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "go.opentelemetry.io/collector/processor" 21 | "go.opentelemetry.io/collector/processor/batchprocessor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return batchprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/coldstart.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.coldstart) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" 21 | "go.opentelemetry.io/collector/processor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return coldstartprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/decouple.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.decouple) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor" 21 | "go.opentelemetry.io/collector/processor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return decoupleprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/filter.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.filter) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor" 21 | "go.opentelemetry.io/collector/processor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return filterprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/memorylimiter.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.memorylimiter) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "go.opentelemetry.io/collector/processor" 21 | "go.opentelemetry.io/collector/processor/memorylimiterprocessor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return memorylimiterprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/pkg.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package processor 16 | 17 | import "go.opentelemetry.io/collector/processor" 18 | 19 | var Factories []func(extensionId string) processor.Factory -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/probabilisticsampler.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.probabilisticsampler) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor" 21 | "go.opentelemetry.io/collector/processor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return probabilisticsamplerprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/resource.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.resource) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor" 21 | "go.opentelemetry.io/collector/processor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return resourceprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/processor/span.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.processor.all || lambdacomponents.processor.span) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package processor 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-collector-contrib/processor/spanprocessor" 21 | "go.opentelemetry.io/collector/processor" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) processor.Factory { 26 | return spanprocessor.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/receiver/otlp.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.receiver.all || lambdacomponents.receiver.otlp) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package receiver 18 | 19 | import ( 20 | "go.opentelemetry.io/collector/receiver" 21 | "go.opentelemetry.io/collector/receiver/otlpreceiver" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) receiver.Factory { 26 | return otlpreceiver.NewFactory() 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdacomponents/receiver/pkg.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package receiver 16 | 17 | import "go.opentelemetry.io/collector/receiver" 18 | 19 | var Factories []func(extensionId string) receiver.Factory -------------------------------------------------------------------------------- /collector/lambdacomponents/receiver/telemetryapi.go: -------------------------------------------------------------------------------- 1 | //go:build lambdacomponents.custom && (lambdacomponents.all || lambdacomponents.receiver.all || lambdacomponents.receiver.telemetryapi) 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package receiver 18 | 19 | import ( 20 | "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver" 21 | "go.opentelemetry.io/collector/receiver" 22 | ) 23 | 24 | func init() { 25 | Factories = append(Factories, func(extensionId string) receiver.Factory { 26 | return telemetryapireceiver.NewFactory(extensionId) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /collector/lambdalifecycle/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.Common 2 | -------------------------------------------------------------------------------- /collector/lambdalifecycle/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/open-telemetry/opentelemetry-lambda/collector/lambdalifecycle 2 | 3 | go 1.24.2 4 | -------------------------------------------------------------------------------- /collector/lambdalifecycle/notifier.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package lambdalifecycle 16 | 17 | // Listener interface used to notify objects of Lambda lifecycle events. 18 | type Listener interface { 19 | // FunctionInvoked is called after the extension receives a "Next" notification. 20 | FunctionInvoked() 21 | // FunctionFinished is called after the extension is notified that the function has completed, but before the environment is frozen. 22 | // The environment is only frozen once all listeners have returned. 23 | FunctionFinished() 24 | // EnvironmentShutdown is called when the extension is notified that the environment is about to shut down. 25 | // Shutting down of the collector components only happens after all listeners have returned. 26 | EnvironmentShutdown() 27 | } 28 | 29 | type Notifier interface { 30 | AddListener(listener Listener) 31 | } 32 | 33 | var ( 34 | notifier Notifier 35 | ) 36 | 37 | func SetNotifier(n Notifier) { 38 | notifier = n 39 | } 40 | 41 | func GetNotifier() Notifier { 42 | return notifier 43 | } 44 | -------------------------------------------------------------------------------- /collector/main.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "flag" 20 | "fmt" 21 | "os" 22 | 23 | "github.com/open-telemetry/opentelemetry-lambda/collector/lambdalifecycle" 24 | 25 | "go.uber.org/zap" 26 | "go.uber.org/zap/zapcore" 27 | 28 | "github.com/open-telemetry/opentelemetry-lambda/collector/internal/lifecycle" 29 | ) 30 | 31 | var ( 32 | // Version variable will be replaced at link time after `make` has been run. 33 | Version = "latest" 34 | 35 | // GitHash variable will be replaced at link time after `make` has been run. 36 | GitHash = "" 37 | ) 38 | 39 | func main() { 40 | versionFlag := flag.Bool("v", false, "prints version information") 41 | flag.Parse() 42 | if *versionFlag { 43 | fmt.Println(Version) 44 | return 45 | } 46 | 47 | logger := initLogger() 48 | logger.Info("Launching OpenTelemetry Lambda extension", zap.String("version", Version)) 49 | 50 | ctx, lm := lifecycle.NewManager(context.Background(), logger, Version) 51 | 52 | // Set the new lifecycle manager as the lifecycle notifier for all other components. 53 | lambdalifecycle.SetNotifier(lm) 54 | 55 | // Will block until shutdown event is received or cancelled via the context. 56 | logger.Info("done", zap.Error(lm.Run(ctx))) 57 | } 58 | 59 | func initLogger() *zap.Logger { 60 | lvl := zap.NewAtomicLevelAt(zapcore.InfoLevel) 61 | envLvl := os.Getenv("OPENTELEMETRY_EXTENSION_LOG_LEVEL") 62 | // When not set, Getenv returns empty string 63 | var err error 64 | if envLvl != "" { 65 | var userLvl zap.AtomicLevel 66 | userLvl, err = zap.ParseAtomicLevel(envLvl) 67 | if err == nil { 68 | lvl = userLvl 69 | } 70 | } 71 | 72 | l := zap.New(zapcore.NewCore(zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), os.Stdout, lvl)) 73 | 74 | if err != nil && envLvl != "" { 75 | l.Warn("unable to parse log level from environment", zap.Error(err)) 76 | } 77 | 78 | return l 79 | } 80 | -------------------------------------------------------------------------------- /collector/processor/coldstartprocessor/Makefile: -------------------------------------------------------------------------------- 1 | include ../../Makefile.Common 2 | -------------------------------------------------------------------------------- /collector/processor/coldstartprocessor/README.md: -------------------------------------------------------------------------------- 1 | # Coldstart Processor 2 | 3 | | Status | | 4 | | ------------------------ |-----------------| 5 | | Stability | [alpha] | 6 | | Supported pipeline types | traces | 7 | | Distributions | [extension] | 8 | 9 | This processor associates cold start information generated by the [telemetryapireceiver](../../receiver/telemetryapireceiver) with incoming span data processed by 10 | the Collector extension. It reads the following of incoming Lambda execution spans identified by the `faas.execution` attribute: 11 | 12 | - trace ID 13 | - parent span ID 14 | - span scope 15 | - resource attributes 16 | 17 | This information is stored until the first coldstart span identified by the `faas.coldstart` attribute 18 | is received. That span's trace ID, parent span ID are updated to match the execution span. This 19 | allows the coldstart span to be part of the same trace as the operation that triggered the cold start. Additionally, 20 | the span scope and resource attributes of the span scope containing the coldstart span 21 | are replaced with the span scope and resource attributes of the execution span as 22 | they contain more details. 23 | 24 | There are currently no configuration parameters available for this processor. It can be enabled via the following configuration: 25 | 26 | ```yaml 27 | processors: 28 | coldstart: 29 | ``` 30 | 31 | [alpha]: https://github.com/open-telemetry/opentelemetry-collector#alpha 32 | [extension]: https://github.com/open-telemetry/opentelemetry-lambda/collector 33 | -------------------------------------------------------------------------------- /collector/processor/coldstartprocessor/config.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" 16 | 17 | // Config defines the configuration for the various elements of the processor. 18 | type Config struct{} 19 | 20 | // Validate validates the configuration by checking for missing or invalid fields 21 | func (cfg *Config) Validate() error { 22 | return nil 23 | } 24 | -------------------------------------------------------------------------------- /collector/processor/coldstartprocessor/config_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/stretchr/testify/require" 21 | ) 22 | 23 | func TestValidate(t *testing.T) { 24 | testCases := []struct { 25 | desc string 26 | cfg *Config 27 | expectedErr error 28 | }{ 29 | { 30 | desc: "valid config", 31 | cfg: &Config{}, 32 | expectedErr: nil, 33 | }, 34 | } 35 | 36 | for _, tc := range testCases { 37 | t.Run(tc.desc, func(t *testing.T) { 38 | actualErr := tc.cfg.Validate() 39 | if tc.expectedErr != nil { 40 | require.EqualError(t, actualErr, tc.expectedErr.Error()) 41 | } else { 42 | require.NoError(t, actualErr) 43 | } 44 | 45 | }) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /collector/processor/coldstartprocessor/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package coldstartprocessor correlates cold start information generated by the telemetryapireceiver 16 | // with incoming span data. 17 | // 18 | // It reads the following of incoming Lambda execution spans identified by the faas.execution attribute: 19 | // 20 | // - trace ID 21 | // - parent span ID 22 | // - span scope 23 | // - resource attributes 24 | // 25 | // This information is stored until the first coldstart span identified by the faas.coldstart attribute 26 | // is received. That span's trace ID, parent span ID are updated to match the execution span. This 27 | // allows the coldstart span to be part of the same trace as the operation that triggered the cold start. Additionally, 28 | // the span scope and resource attributes of the span scope containing the coldstart span 29 | // are replaced with the span scope and resource attributes of the execution span as 30 | // they contain more details. 31 | package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" 32 | -------------------------------------------------------------------------------- /collector/processor/coldstartprocessor/factory.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" 16 | 17 | import ( 18 | "context" 19 | "errors" 20 | 21 | "go.opentelemetry.io/collector/component" 22 | "go.opentelemetry.io/collector/consumer" 23 | "go.opentelemetry.io/collector/processor" 24 | "go.opentelemetry.io/collector/processor/processorhelper" 25 | ) 26 | 27 | const ( 28 | typeStr = "coldstart" 29 | stability = component.StabilityLevelDevelopment 30 | ) 31 | 32 | var ( 33 | Type = component.MustNewType(typeStr) 34 | errConfigNotColdstart = errors.New("config was not a Coldstart processor config") 35 | processorCapabilities = consumer.Capabilities{MutatesData: true} 36 | ) 37 | 38 | func NewFactory() processor.Factory { 39 | return processor.NewFactory( 40 | Type, 41 | createDefaultConfig, 42 | processor.WithTraces(createTracesProcessor, stability), 43 | ) 44 | } 45 | 46 | func createDefaultConfig() component.Config { 47 | return &Config{} 48 | } 49 | 50 | func createTracesProcessor(ctx context.Context, params processor.Settings, rConf component.Config, next consumer.Traces) (processor.Traces, error) { 51 | cfg, ok := rConf.(*Config) 52 | if !ok { 53 | return nil, errConfigNotColdstart 54 | } 55 | 56 | cp, err := newColdstartProcessor(cfg, next, params) 57 | if err != nil { 58 | return nil, err 59 | } 60 | return processorhelper.NewTraces( 61 | ctx, 62 | params, 63 | cfg, 64 | next, 65 | cp.processTraces, 66 | processorhelper.WithCapabilities(processorCapabilities), 67 | ) 68 | 69 | } 70 | -------------------------------------------------------------------------------- /collector/processor/coldstartprocessor/factory_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package coldstartprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor" 16 | 17 | import ( 18 | "context" 19 | "testing" 20 | 21 | "github.com/stretchr/testify/require" 22 | "go.opentelemetry.io/collector/consumer/consumertest" 23 | "go.opentelemetry.io/collector/processor/processortest" 24 | ) 25 | 26 | func TestNewFactory(t *testing.T) { 27 | testCases := []struct { 28 | desc string 29 | testFunc func(*testing.T) 30 | }{ 31 | { 32 | desc: "creates a new factory with correct type", 33 | testFunc: func(t *testing.T) { 34 | factory := NewFactory() 35 | require.EqualValues(t, typeStr, factory.Type().String()) 36 | }, 37 | }, 38 | { 39 | desc: "creates a new factory and CreateTracesProcessor returns no error", 40 | testFunc: func(t *testing.T) { 41 | factory := NewFactory() 42 | cfg := factory.CreateDefaultConfig() 43 | _, err := factory.CreateTraces( 44 | context.Background(), 45 | processortest.NewNopSettings(Type), 46 | cfg, 47 | consumertest.NewNop(), 48 | ) 49 | require.NoError(t, err) 50 | }, 51 | }, 52 | { 53 | desc: "creates a new factory and CreateTracesProcessor returns error with incorrect config", 54 | testFunc: func(t *testing.T) { 55 | factory := NewFactory() 56 | _, err := factory.CreateTraces( 57 | context.Background(), 58 | processortest.NewNopSettings(Type), 59 | nil, 60 | consumertest.NewNop(), 61 | ) 62 | require.ErrorIs(t, err, errConfigNotColdstart) 63 | }, 64 | }, 65 | } 66 | 67 | for _, tc := range testCases { 68 | t.Run(tc.desc, tc.testFunc) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /collector/processor/coldstartprocessor/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/open-telemetry/opentelemetry-lambda/collector/processor/coldstartprocessor 2 | 3 | go 1.24.2 4 | 5 | require ( 6 | github.com/cespare/xxhash v1.1.0 7 | github.com/stretchr/testify v1.10.0 8 | go.opentelemetry.io/collector/component v1.33.0 9 | go.opentelemetry.io/collector/consumer v1.33.0 10 | go.opentelemetry.io/collector/consumer/consumertest v0.127.0 11 | go.opentelemetry.io/collector/pdata v1.33.0 12 | go.opentelemetry.io/collector/processor v1.33.0 13 | go.opentelemetry.io/collector/processor/processorhelper v0.127.0 14 | go.opentelemetry.io/collector/processor/processortest v0.127.0 15 | go.opentelemetry.io/collector/semconv v0.127.0 16 | go.uber.org/multierr v1.11.0 17 | go.uber.org/zap v1.27.0 18 | ) 19 | 20 | require ( 21 | github.com/davecgh/go-spew v1.1.1 // indirect 22 | github.com/go-logr/logr v1.4.2 // indirect 23 | github.com/go-logr/stdr v1.2.2 // indirect 24 | github.com/gogo/protobuf v1.3.2 // indirect 25 | github.com/google/uuid v1.6.0 // indirect 26 | github.com/hashicorp/go-version v1.7.0 // indirect 27 | github.com/json-iterator/go v1.1.12 // indirect 28 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 29 | github.com/modern-go/reflect2 v1.0.2 // indirect 30 | github.com/pmezard/go-difflib v1.0.0 // indirect 31 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 32 | go.opentelemetry.io/collector/component/componentstatus v0.127.0 // indirect 33 | go.opentelemetry.io/collector/component/componenttest v0.127.0 // indirect 34 | go.opentelemetry.io/collector/consumer/xconsumer v0.127.0 // indirect 35 | go.opentelemetry.io/collector/featuregate v1.33.0 // indirect 36 | go.opentelemetry.io/collector/internal/telemetry v0.127.0 // indirect 37 | go.opentelemetry.io/collector/pdata/pprofile v0.127.0 // indirect 38 | go.opentelemetry.io/collector/pdata/testdata v0.127.0 // indirect 39 | go.opentelemetry.io/collector/pipeline v0.127.0 // indirect 40 | go.opentelemetry.io/collector/processor/xprocessor v0.127.0 // indirect 41 | go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 // indirect 42 | go.opentelemetry.io/otel v1.36.0 // indirect 43 | go.opentelemetry.io/otel/log v0.11.0 // indirect 44 | go.opentelemetry.io/otel/metric v1.36.0 // indirect 45 | go.opentelemetry.io/otel/sdk v1.35.0 // indirect 46 | go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect 47 | go.opentelemetry.io/otel/trace v1.36.0 // indirect 48 | golang.org/x/net v0.39.0 // indirect 49 | golang.org/x/sys v0.32.0 // indirect 50 | golang.org/x/text v0.24.0 // indirect 51 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect 52 | google.golang.org/grpc v1.72.1 // indirect 53 | google.golang.org/protobuf v1.36.6 // indirect 54 | gopkg.in/yaml.v3 v3.0.1 // indirect 55 | ) 56 | -------------------------------------------------------------------------------- /collector/processor/decoupleprocessor/Makefile: -------------------------------------------------------------------------------- 1 | include ../../Makefile.Common 2 | -------------------------------------------------------------------------------- /collector/processor/decoupleprocessor/config.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package decoupleprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor" 16 | import "errors" 17 | 18 | // Config defines the configuration for the various elements of the processor. 19 | type Config struct { 20 | MaxQueueSize uint32 `mapstructure:"max_queue_size"` 21 | } 22 | 23 | var invalidMaxQueueSizeError = errors.New("max_queue_size must be greater than 0") 24 | 25 | // Validate validates the configuration by checking for missing or invalid fields 26 | func (cfg *Config) Validate() error { 27 | if cfg.MaxQueueSize == 0 { 28 | return invalidMaxQueueSizeError 29 | } 30 | return nil 31 | } 32 | -------------------------------------------------------------------------------- /collector/processor/decoupleprocessor/config_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package decoupleprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor" 16 | 17 | import ( 18 | "path/filepath" 19 | "testing" 20 | 21 | "go.opentelemetry.io/collector/component" 22 | "go.opentelemetry.io/collector/confmap/confmaptest" 23 | "go.opentelemetry.io/collector/confmap/xconfmap" 24 | 25 | "github.com/stretchr/testify/assert" 26 | "github.com/stretchr/testify/require" 27 | ) 28 | 29 | func TestValidate(t *testing.T) { 30 | testCases := []struct { 31 | desc string 32 | cfg *Config 33 | expectedErr error 34 | }{ 35 | { 36 | desc: "valid config", 37 | cfg: &Config{ 38 | MaxQueueSize: 1, 39 | }, 40 | expectedErr: nil, 41 | }, 42 | { 43 | desc: "invalid config", 44 | cfg: &Config{}, 45 | expectedErr: invalidMaxQueueSizeError, 46 | }, 47 | } 48 | 49 | for _, tc := range testCases { 50 | t.Run(tc.desc, func(t *testing.T) { 51 | actualErr := tc.cfg.Validate() 52 | if tc.expectedErr != nil { 53 | require.EqualError(t, actualErr, tc.expectedErr.Error()) 54 | } else { 55 | require.NoError(t, actualErr) 56 | } 57 | 58 | }) 59 | } 60 | } 61 | 62 | func TestLoadConfig(t *testing.T) { 63 | t.Parallel() 64 | 65 | tests := []struct { 66 | id component.ID 67 | expected component.Config 68 | }{ 69 | { 70 | id: component.NewIDWithName(component.MustNewType(typeStr), ""), 71 | expected: &Config{ 72 | MaxQueueSize: 100, 73 | }, 74 | }, 75 | { 76 | id: component.NewIDWithName(component.MustNewType(typeStr), "empty"), 77 | expected: createDefaultConfig(), 78 | }, 79 | } 80 | 81 | for _, tt := range tests { 82 | t.Run(tt.id.String(), func(t *testing.T) { 83 | cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) 84 | require.NoError(t, err) 85 | 86 | factory := NewFactory() 87 | cfg := factory.CreateDefaultConfig() 88 | 89 | sub, err := cm.Sub(tt.id.String()) 90 | require.NoError(t, err) 91 | require.NoError(t, sub.Unmarshal(cfg)) 92 | 93 | assert.NoError(t, xconfmap.Validate(cfg)) 94 | assert.Equal(t, tt.expected, cfg) 95 | }) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /collector/processor/decoupleprocessor/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package decoupleprocessor allows the receiver and export sides of a pipeline to be decoupled and allow the 16 | // receiver to return while the export side is still executing. 17 | package decoupleprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor" 18 | -------------------------------------------------------------------------------- /collector/processor/decoupleprocessor/factory_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package decoupleprocessor // import "github.com/open-telemetry/opentelemetry-lambda/collector/processor/decoupleprocessor" 16 | 17 | import ( 18 | "context" 19 | "testing" 20 | 21 | "github.com/open-telemetry/opentelemetry-lambda/collector/lambdalifecycle" 22 | 23 | "github.com/stretchr/testify/require" 24 | "go.opentelemetry.io/collector/consumer/consumertest" 25 | "go.opentelemetry.io/collector/processor/processortest" 26 | ) 27 | 28 | func TestNewFactory(t *testing.T) { 29 | lambdalifecycle.SetNotifier(&MockLifecycleNotifier{}) 30 | testCases := []struct { 31 | desc string 32 | testFunc func(*testing.T) 33 | }{ 34 | { 35 | desc: "creates a new factory with correct type", 36 | testFunc: func(t *testing.T) { 37 | factory := NewFactory() 38 | require.EqualValues(t, typeStr, factory.Type().String()) 39 | }, 40 | }, 41 | { 42 | desc: "creates a new factory and CreateTracesProcessor returns no error", 43 | testFunc: func(t *testing.T) { 44 | factory := NewFactory() 45 | cfg := factory.CreateDefaultConfig() 46 | _, err := factory.CreateTraces( 47 | context.Background(), 48 | processortest.NewNopSettings(Type), 49 | cfg, 50 | consumertest.NewNop(), 51 | ) 52 | require.NoError(t, err) 53 | }, 54 | }, 55 | { 56 | desc: "creates a new factory and CreateTracesProcessor returns error with incorrect config", 57 | testFunc: func(t *testing.T) { 58 | factory := NewFactory() 59 | _, err := factory.CreateTraces( 60 | context.Background(), 61 | processortest.NewNopSettings(Type), 62 | nil, 63 | consumertest.NewNop(), 64 | ) 65 | require.ErrorIs(t, err, errConfigNotDecouple) 66 | }, 67 | }, 68 | } 69 | 70 | for _, tc := range testCases { 71 | t.Run(tc.desc, tc.testFunc) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /collector/processor/decoupleprocessor/testdata/config.yaml: -------------------------------------------------------------------------------- 1 | decouple: 2 | max_queue_size: 100 3 | 4 | decouple/empty: -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/Makefile: -------------------------------------------------------------------------------- 1 | include ../../Makefile.Common 2 | -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/README.md: -------------------------------------------------------------------------------- 1 | # Telemetry API Receiver 2 | 3 | | Status | | 4 | | ------------------------ |--------------| 5 | | Stability | [alpha] | 6 | | Supported pipeline types | traces, logs | 7 | | Distributions | [extension] | 8 | 9 | This receiver generates telemetry in response to events from the [Telemetry API](https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api.html). It does this by setting up an endpoint and registering itself with the Telemetry API on startup. 10 | 11 | Supported events: 12 | 13 | * `platform.initStart` - The receiver uses this event to record the start time of the function initialization period. Once both start and end times are recorded, the receiver generates a span named `platform.initRuntimeDone` to record the event. 14 | * `platform.initRuntimeDone` - The receiver uses this event to record the end time of the function initialization period. Once both start and end times are recorded, the receiver generates a span named `platform.initRuntimeDone` to record the event. 15 | 16 | ## Configuration 17 | 18 | | Field | Default | Description | 19 | |---------|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| 20 | | `port` | 4325 | HTTP server port to receive Telemetry API data. | 21 | | `types` | ["platform", "function", "extension"] | [Types](https://docs.aws.amazon.com/lambda/latest/dg/telemetry-api-reference.html#telemetry-subscribe-api) of telemetry to subscribe to | 22 | 23 | 24 | ```yaml 25 | receivers: 26 | telemetryapi: 27 | telemetryapi/1: 28 | port: 4326 29 | telemetryapi/2: 30 | port: 4327 31 | types: 32 | - platform 33 | - function 34 | telemetryapi/3: 35 | port: 4328 36 | types: ["platform", "function"] 37 | ``` 38 | 39 | [alpha]: https://github.com/open-telemetry/opentelemetry-collector#alpha 40 | [extension]: https://github.com/open-telemetry/opentelemetry-lambda/collector 41 | -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/config.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver" 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | // Config defines the configuration for the various elements of the receiver agent. 22 | type Config struct { 23 | extensionID string 24 | Port int `mapstructure:"port"` 25 | Types []string `mapstructure:"types"` 26 | } 27 | 28 | // Validate validates the configuration by checking for missing or invalid fields 29 | func (cfg *Config) Validate() error { 30 | for _, t := range cfg.Types { 31 | if t != platform && t != function && t != extension { 32 | return fmt.Errorf("unknown extension type: %s", t) 33 | } 34 | } 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package telemetryapireceiver generates telemetry in response to events from the Telemetry API. 16 | package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver" 17 | -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/factory_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver" 16 | 17 | import ( 18 | "context" 19 | "testing" 20 | 21 | "github.com/stretchr/testify/require" 22 | "go.opentelemetry.io/collector/component" 23 | "go.opentelemetry.io/collector/consumer/consumertest" 24 | "go.opentelemetry.io/collector/receiver/receivertest" 25 | ) 26 | 27 | func TestNewFactory(t *testing.T) { 28 | testCases := []struct { 29 | desc string 30 | testFunc func(*testing.T) 31 | }{ 32 | { 33 | desc: "creates a new factory with correct type", 34 | testFunc: func(t *testing.T) { 35 | factory := NewFactory("test") 36 | require.EqualValues(t, typeStr, factory.Type().String()) 37 | }, 38 | }, 39 | { 40 | desc: "creates a new factory with valid default config", 41 | testFunc: func(t *testing.T) { 42 | factory := NewFactory("test") 43 | 44 | var expectedCfg component.Config = &Config{extensionID: "test", Port: defaultPort, Types: []string{platform, function, extension}} 45 | 46 | require.Equal(t, expectedCfg, factory.CreateDefaultConfig()) 47 | }, 48 | }, 49 | { 50 | desc: "creates a new factory and CreateTracesReceiver returns no error", 51 | testFunc: func(t *testing.T) { 52 | factory := NewFactory("test") 53 | cfg := factory.CreateDefaultConfig() 54 | _, err := factory.CreateTraces( 55 | context.Background(), 56 | receivertest.NewNopSettings(Type), 57 | cfg, 58 | consumertest.NewNop(), 59 | ) 60 | require.NoError(t, err) 61 | }, 62 | }, 63 | { 64 | desc: "creates a new factory and CreateTracesReceiver returns error with incorrect config", 65 | testFunc: func(t *testing.T) { 66 | factory := NewFactory("test") 67 | _, err := factory.CreateTraces( 68 | context.Background(), 69 | receivertest.NewNopSettings(Type), 70 | nil, 71 | consumertest.NewNop(), 72 | ) 73 | require.ErrorIs(t, err, errConfigNotTelemetryAPI) 74 | }, 75 | }, 76 | } 77 | 78 | for _, tc := range testCases { 79 | t.Run(tc.desc, tc.testFunc) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/internal/sharedcomponent/sharedcomponent.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package sharedcomponent exposes util functionality for receivers and exporters 5 | // that need to share state between different signal types instances such as net.Listener or os.File. 6 | package sharedcomponent // import "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver/internal/sharedcomponent" 7 | 8 | import ( 9 | "context" 10 | "sync" 11 | 12 | "go.opentelemetry.io/collector/component" 13 | ) 14 | 15 | // SharedComponents a map that keeps reference of all created instances for a given configuration, 16 | // and ensures that the shared state is started and stopped only once. 17 | type SharedComponents struct { 18 | comps map[any]*SharedComponent 19 | } 20 | 21 | // NewSharedComponents returns a new empty SharedComponents. 22 | func NewSharedComponents() *SharedComponents { 23 | return &SharedComponents{ 24 | comps: make(map[any]*SharedComponent), 25 | } 26 | } 27 | 28 | // GetOrAdd returns the already created instance if exists, otherwise creates a new instance 29 | // and adds it to the map of references. 30 | func (scs *SharedComponents) GetOrAdd(key any, create func() component.Component) *SharedComponent { 31 | if c, ok := scs.comps[key]; ok { 32 | return c 33 | } 34 | newComp := &SharedComponent{ 35 | Component: create(), 36 | removeFunc: func() { 37 | delete(scs.comps, key) 38 | }, 39 | } 40 | scs.comps[key] = newComp 41 | return newComp 42 | } 43 | 44 | // SharedComponent ensures that the wrapped component is started and stopped only once. 45 | // When stopped it is removed from the SharedComponents map. 46 | type SharedComponent struct { 47 | component.Component 48 | 49 | startOnce sync.Once 50 | stopOnce sync.Once 51 | removeFunc func() 52 | } 53 | 54 | // Unwrap returns the original component. 55 | func (r *SharedComponent) Unwrap() component.Component { 56 | return r.Component 57 | } 58 | 59 | // Start implements component.Component. 60 | func (r *SharedComponent) Start(ctx context.Context, host component.Host) error { 61 | var err error 62 | r.startOnce.Do(func() { 63 | err = r.Component.Start(ctx, host) 64 | }) 65 | return err 66 | } 67 | 68 | // Shutdown implements component.Component. 69 | func (r *SharedComponent) Shutdown(ctx context.Context) error { 70 | var err error 71 | r.stopOnce.Do(func() { 72 | err = r.Component.Shutdown(ctx) 73 | r.removeFunc() 74 | }) 75 | return err 76 | } 77 | -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/internal/sharedcomponent/sharedcomponent_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package sharedcomponent 5 | 6 | import ( 7 | "context" 8 | "errors" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "go.opentelemetry.io/collector/component" 13 | "go.opentelemetry.io/collector/component/componenttest" 14 | ) 15 | 16 | var id = component.MustNewID("test") 17 | 18 | func TestNewSharedComponents(t *testing.T) { 19 | comps := NewSharedComponents() 20 | assert.Len(t, comps.comps, 0) 21 | } 22 | 23 | type mockComponent struct { 24 | component.StartFunc 25 | component.ShutdownFunc 26 | } 27 | 28 | func TestSharedComponents_GetOrAdd(t *testing.T) { 29 | nop := &mockComponent{} 30 | createNop := func() component.Component { return nop } 31 | 32 | comps := NewSharedComponents() 33 | got := comps.GetOrAdd(id, createNop) 34 | assert.Len(t, comps.comps, 1) 35 | assert.Same(t, nop, got.Unwrap()) 36 | assert.Same(t, got, comps.GetOrAdd(id, createNop)) 37 | 38 | // Shutdown nop will remove 39 | assert.NoError(t, got.Shutdown(context.Background())) 40 | assert.Len(t, comps.comps, 0) 41 | assert.NotSame(t, got, comps.GetOrAdd(id, createNop)) 42 | } 43 | 44 | func TestSharedComponent(t *testing.T) { 45 | wantErr := errors.New("my error") 46 | calledStart := 0 47 | calledStop := 0 48 | comp := &mockComponent{ 49 | StartFunc: func(_ context.Context, _ component.Host) error { 50 | calledStart++ 51 | return wantErr 52 | }, 53 | ShutdownFunc: func(_ context.Context) error { 54 | calledStop++ 55 | return wantErr 56 | }, 57 | } 58 | createComp := func() component.Component { return comp } 59 | 60 | comps := NewSharedComponents() 61 | got := comps.GetOrAdd(id, createComp) 62 | assert.Equal(t, wantErr, got.Start(context.Background(), componenttest.NewNopHost())) 63 | assert.Equal(t, 1, calledStart) 64 | // Second time is not called anymore. 65 | assert.NoError(t, got.Start(context.Background(), componenttest.NewNopHost())) 66 | assert.Equal(t, 1, calledStart) 67 | assert.Equal(t, wantErr, got.Shutdown(context.Background())) 68 | assert.Equal(t, 1, calledStop) 69 | // Second time is not called anymore. 70 | assert.NoError(t, got.Shutdown(context.Background())) 71 | assert.Equal(t, 1, calledStop) 72 | } 73 | -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/testdata/config.yaml: -------------------------------------------------------------------------------- 1 | telemetryapi: 2 | telemetryapi/1: 3 | port: 12345 4 | telemetryapi/2: 5 | port: 12345 6 | types: ["platform"] 7 | telemetryapi/3: 8 | port: 12345 9 | types: ["function"] 10 | telemetryapi/4: 11 | port: 12345 12 | types: ["extension"] 13 | telemetryapi/5: 14 | port: 12345 15 | types: ["platform", "function"] 16 | telemetryapi/6: 17 | port: 12345 18 | types: ["platform", "extension"] 19 | telemetryapi/7: 20 | port: 12345 21 | types: ["function", "extension"] 22 | telemetryapi/8: 23 | port: 12345 24 | types: [] 25 | telemetryapi/9: 26 | port: 12345 27 | types: 28 | - function 29 | - extension 30 | telemetryapi/10: 31 | port: 12345 32 | types: [function, extension] 33 | -------------------------------------------------------------------------------- /collector/receiver/telemetryapireceiver/types.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package telemetryapireceiver // import "github.com/open-telemetry/opentelemetry-lambda/collector/receiver/telemetryapireceiver" 16 | 17 | type event struct { 18 | Time string `json:"time"` 19 | Type string `json:"type"` 20 | Record any `json:"record"` 21 | } 22 | -------------------------------------------------------------------------------- /dotnet/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Lambda .NET 2 | 3 | Nuget package for running .NET applications on AWS Lambda with OpenTelemetry. 4 | 5 | ## Provided SDK 6 | 7 | [OpenTelemetry Lambda SDK for .NET](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/tree/main/src/OpenTelemetry.Instrumentation.AWSLambda) includes tracing APIs to instrument Lambda handler and is provided on [Nuget](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.AWSLambda/1.1.0-beta2). Follow the instructions on [user guide](https://aws-otel.github.io/docs/getting-started/lambda/lambda-dotnet#instrumentation) to manually instrument the Lambda handler. 8 | For other instrumentations, such as http, you'll need to include the corresponding library instrumentation from the [instrumentation project](https://github.com/open-telemetry/opentelemetry-dotnet) and modify your code to initialize it in your function. 9 | 10 | ## Provided Layer 11 | 12 | [OpenTelemetry Lambda Layer for Collector](https://aws-otel.github.io/docs/getting-started/lambda/lambda-dotnet#lambda-layer) includes OpenTelemetry Collector for Lambda components. Follow [user guide](https://aws-otel.github.io/docs/getting-started/lambda/lambda-dotnet#enable-tracing) to apply this layer to your Lambda handler that's already been instrumented with OpenTelemetry Lambda .NET SDK to enable end-to-end tracing. 13 | 14 | ## Sample application 15 | 16 | The [sample application](https://github.com/open-telemetry/opentelemetry-lambda/blob/main/dotnet/sample-apps/aws-sdk/wrapper/SampleApps/AwsSdkSample/Function.cs) shows the manual instrumentations of OpenTelemetry Lambda .NET SDK on a Lambda handler that triggers a downstream request to AWS S3. 17 | -------------------------------------------------------------------------------- /dotnet/sample-apps/aws-sdk/deploy/wrapper/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "AwsSdkSample::AwsSdkSample.Function::TracingFunctionHandler" 8 | runtime = "dotnet6" 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../wrapper/SampleApps/build/function.zip" 12 | 13 | memory_size = 384 14 | timeout = 20 15 | 16 | layers = compact([ 17 | var.collector_layer_arn 18 | ]) 19 | 20 | tracing_mode = var.tracing_mode 21 | 22 | attach_policy_statements = true 23 | policy_statements = { 24 | s3 = { 25 | effect = "Allow" 26 | actions = [ 27 | "s3:ListAllMyBuckets" 28 | ] 29 | resources = [ 30 | "*" 31 | ] 32 | } 33 | } 34 | } 35 | 36 | module "api-gateway" { 37 | source = "../../../../../utils/terraform/api-gateway-proxy" 38 | 39 | name = var.name 40 | function_name = module.hello-lambda-function.lambda_function_name 41 | function_invoke_arn = module.hello-lambda-function.lambda_function_invoke_arn 42 | enable_xray_tracing = var.tracing_mode == "Active" 43 | } 44 | -------------------------------------------------------------------------------- /dotnet/sample-apps/aws-sdk/deploy/wrapper/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api-gateway-url" { 2 | value = module.api-gateway.api_gateway_url 3 | } 4 | 5 | output "function_role_name" { 6 | value = module.hello-lambda-function.lambda_role_name 7 | } 8 | -------------------------------------------------------------------------------- /dotnet/sample-apps/aws-sdk/deploy/wrapper/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-dotnet-awssdk-wrapper" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | } 11 | 12 | variable "tracing_mode" { 13 | type = string 14 | description = "Lambda function tracing mode" 15 | default = "PassThrough" 16 | } 17 | 18 | variable "architecture" { 19 | type = string 20 | description = "Lambda function architecture, valid values are arm64 or x86_64" 21 | default = "x86_64" 22 | } 23 | -------------------------------------------------------------------------------- /dotnet/sample-apps/aws-sdk/wrapper/SampleApps/AwsSdkSample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31112.23 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AwsSdkSample", "AwsSdkSample\AwsSdkSample.csproj", "{5D474E1F-C49C-486D-9398-5D8523D7C722}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {5D474E1F-C49C-486D-9398-5D8523D7C722}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {5D474E1F-C49C-486D-9398-5D8523D7C722}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {5D474E1F-C49C-486D-9398-5D8523D7C722}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {5D474E1F-C49C-486D-9398-5D8523D7C722}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {EB75E573-89CA-4362-8A48-148AB6295EF8} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /dotnet/sample-apps/aws-sdk/wrapper/SampleApps/AwsSdkSample/AwsSdkSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | Lambda 6 | 7 | 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /dotnet/sample-apps/aws-sdk/wrapper/SampleApps/AwsSdkSample/Function.cs: -------------------------------------------------------------------------------- 1 | using Amazon.Lambda.APIGatewayEvents; 2 | using Amazon.Lambda.Core; 3 | using Amazon.S3; 4 | using OpenTelemetry; 5 | using OpenTelemetry.Contrib.Instrumentation.AWSLambda.Implementation; 6 | using OpenTelemetry.Trace; 7 | using System; 8 | 9 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 10 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] 11 | 12 | namespace AwsSdkSample 13 | { 14 | public class Function 15 | { 16 | public static TracerProvider tracerProvider; 17 | 18 | static Function() 19 | { 20 | AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); 21 | 22 | tracerProvider = Sdk.CreateTracerProviderBuilder() 23 | .AddAWSInstrumentation() 24 | .AddOtlpExporter() 25 | .AddAWSLambdaConfigurations() 26 | .Build(); 27 | } 28 | 29 | // use AwsSdkSample::AwsSdkSample.Function::TracingFunctionHandler as input Lambda handler instead 30 | public APIGatewayProxyResponse TracingFunctionHandler(APIGatewayProxyRequest request, ILambdaContext context) 31 | { 32 | return AWSLambdaWrapper.Trace(tracerProvider, FunctionHandler, request, context); 33 | } 34 | 35 | /// 36 | /// A simple function that takes a APIGatewayProxyRequest and returns a APIGatewayProxyResponse 37 | /// 38 | /// 39 | /// 40 | /// 41 | public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context) 42 | { 43 | var S3Client = new AmazonS3Client(); 44 | _ = S3Client.ListBucketsAsync().Result; 45 | return new APIGatewayProxyResponse() { StatusCode = 200, Body = "Hello Validator!" }; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /dotnet/sample-apps/aws-sdk/wrapper/SampleApps/AwsSdkSample/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", 7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /dotnet/sample-apps/aws-sdk/wrapper/SampleApps/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | GOARCH=${GOARCH-amd64} 5 | 6 | # Chosen from Microsoft's documentation for Runtime Identifier (RIDs) 7 | # See more: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog#linux-rids 8 | if [ "$GOARCH" = "amd64" ]; then 9 | DOTNET_LINUX_ARCH=x64 10 | elif [ "$GOARCH" = "arm64" ]; then 11 | DOTNET_LINUX_ARCH=arm64 12 | else 13 | echo "Invalid GOARCH value $(GOARCH) received." 14 | exit 2 15 | fi 16 | 17 | mkdir -p build/dotnet 18 | dotnet publish \ 19 | --output "./build/dotnet" \ 20 | --configuration "Release" \ 21 | --framework "net6.0" /p:GenerateRuntimeConfigurationFiles=true \ 22 | --runtime linux-$DOTNET_LINUX_ARCH \ 23 | --self-contained false 24 | cd build/dotnet 25 | zip -r ../function.zip ./* 26 | -------------------------------------------------------------------------------- /go/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Lambda Go 2 | 3 | Examples of Go applications on AWS Lambda with OpenTelemetry. 4 | 5 | ## Provided SDK 6 | 7 | [OpenTelemetry Lambda SDK for Go](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/github.com/aws/aws-lambda-go/otellambda) includes tracing APIs to instrument Lambda handler. 8 | For other instrumentations, such as http, you'll need to include the corresponding library instrumentation from the [instrumentation project](https://github.com/open-telemetry/opentelemetry-go) and modify your code to use it in your function. 9 | 10 | ## Provided Layer 11 | 12 | [OpenTelemetry Lambda Layer for Collector](https://aws-otel.github.io/docs/getting-started/lambda/lambda-go#lambda-layer) includes OpenTelemetry Collector for Lambda components. Follow [user guide](https://aws-otel.github.io/docs/getting-started/lambda/lambda-go#enable-tracing) to apply this layer to your Lambda handler that's already been instrumented with OpenTelemetry Lambda .NET SDK to enable end-to-end tracing. 13 | 14 | ## Sample application 15 | 16 | The [sample application](https://github.com/open-telemetry/opentelemetry-lambda/tree/main/go/sample-apps/function/function.go) shows the manual instrumentations of OpenTelemetry Lambda Go SDK on a Lambda handler that triggers downstream requests to AWS S3 and HTTP. 17 | -------------------------------------------------------------------------------- /go/sample-apps/aws-sdk/deploy/wrapper/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "bootstrap" 8 | runtime = "provided.al2" 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../../function/build/bootstrap.zip" 12 | 13 | memory_size = 384 14 | timeout = 20 15 | 16 | layers = compact([ 17 | var.collector_layer_arn 18 | ]) 19 | 20 | tracing_mode = var.tracing_mode 21 | 22 | attach_policy_statements = true 23 | policy_statements = { 24 | s3 = { 25 | effect = "Allow" 26 | actions = [ 27 | "s3:ListAllMyBuckets" 28 | ] 29 | resources = [ 30 | "*" 31 | ] 32 | } 33 | } 34 | } 35 | 36 | module "api-gateway" { 37 | source = "../../../../../utils/terraform/api-gateway-proxy" 38 | 39 | name = var.name 40 | function_name = module.hello-lambda-function.lambda_function_name 41 | function_invoke_arn = module.hello-lambda-function.lambda_function_invoke_arn 42 | enable_xray_tracing = var.tracing_mode == "Active" 43 | } 44 | -------------------------------------------------------------------------------- /go/sample-apps/aws-sdk/deploy/wrapper/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api-gateway-url" { 2 | value = module.api-gateway.api_gateway_url 3 | } 4 | 5 | output "function_role_name" { 6 | value = module.hello-lambda-function.lambda_role_name 7 | } 8 | -------------------------------------------------------------------------------- /go/sample-apps/aws-sdk/deploy/wrapper/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-go-awssdk-wrapper" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | } 11 | 12 | variable "tracing_mode" { 13 | type = string 14 | description = "Lambda function tracing mode" 15 | default = "PassThrough" 16 | } 17 | 18 | variable "architecture" { 19 | type = string 20 | description = "Lambda function architecture, valid values are arm64 or x86_64" 21 | default = "x86_64" 22 | } 23 | -------------------------------------------------------------------------------- /go/sample-apps/function/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | GOARCH=${GOARCH-amd64} 5 | 6 | mkdir -p build 7 | CGO_ENABLED=0 GOOS=linux go build -o ./build/bootstrap . 8 | cd build 9 | zip bootstrap.zip bootstrap 10 | -------------------------------------------------------------------------------- /java/awssdk-autoconfigure/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // TODO(anuraaga): Move this into instrumentation repo 2 | 3 | plugins { 4 | `java-library` 5 | } 6 | 7 | base.archivesName = "opentelemetry-lambda-awsdk-autoconfigure" 8 | 9 | dependencies { 10 | compileOnly("io.opentelemetry:opentelemetry-api") 11 | compileOnly("software.amazon.awssdk:aws-core") 12 | 13 | implementation("io.opentelemetry.instrumentation:opentelemetry-aws-sdk-2.2") 14 | } 15 | -------------------------------------------------------------------------------- /java/awssdk-autoconfigure/src/main/resources/software/amazon/awssdk/global/handlers/execution.interceptors: -------------------------------------------------------------------------------- 1 | io.opentelemetry.instrumentation.awssdk.v2_2.autoconfigure.AutoconfiguredTracingExecutionInterceptor 2 | -------------------------------------------------------------------------------- /java/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.diffplug.spotless") 3 | } 4 | 5 | allprojects { 6 | group = "io.opentelemetry.lambda" 7 | 8 | plugins.apply("com.diffplug.spotless") 9 | 10 | plugins.withId("java") { 11 | configure { 12 | sourceCompatibility = JavaVersion.VERSION_1_8 13 | targetCompatibility = JavaVersion.VERSION_1_8 14 | } 15 | 16 | spotless { 17 | java { 18 | googleJavaFormat() 19 | } 20 | } 21 | 22 | dependencies { 23 | afterEvaluate { 24 | configurations.configureEach { 25 | if (!isCanBeResolved && !isCanBeConsumed) { 26 | add(name, enforcedPlatform(project(":dependencyManagement"))) 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /java/dependencyManagement/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask 2 | 3 | plugins { 4 | `java-platform` 5 | 6 | id("com.github.ben-manes.versions") 7 | } 8 | 9 | data class DependencySet(val group: String, val version: String, val modules: List) 10 | 11 | val DEPENDENCY_BOMS = listOf( 12 | "io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:2.16.0-alpha", 13 | "org.apache.logging.log4j:log4j-bom:2.24.3", 14 | "software.amazon.awssdk:bom:2.31.54" 15 | ) 16 | 17 | val DEPENDENCIES = listOf( 18 | "com.amazonaws:aws-lambda-java-core:1.3.0", 19 | "com.amazonaws:aws-lambda-java-events:3.15.0", 20 | "com.squareup.okhttp3:okhttp:4.12.0", 21 | "io.opentelemetry.javaagent:opentelemetry-javaagent:2.16.0", 22 | "io.opentelemetry:opentelemetry-sdk-extension-aws:1.19.0", 23 | "io.opentelemetry.contrib:opentelemetry-aws-resources:1.46.0-alpha", 24 | ) 25 | 26 | javaPlatform { 27 | allowDependencies() 28 | } 29 | 30 | dependencies { 31 | for (bom in DEPENDENCY_BOMS) { 32 | api(platform(bom)) 33 | } 34 | constraints { 35 | for (dependency in DEPENDENCIES) { 36 | api(dependency) 37 | } 38 | } 39 | } 40 | 41 | fun isNonStable(version: String): Boolean { 42 | val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase().contains(it) } 43 | val regex = "^[0-9,.v-]+(-r)?$".toRegex() 44 | val isGuava = version.endsWith("-jre") 45 | val isStable = stableKeyword || regex.matches(version) || isGuava 46 | return isStable.not() 47 | } 48 | 49 | tasks { 50 | named("dependencyUpdates") { 51 | revision = "release" 52 | checkConstraints = true 53 | 54 | rejectVersionIf { 55 | isNonStable(candidate.version) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /java/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.parallel=true 2 | org.gradle.caching=true 3 | org.gradle.vfs.watch=true 4 | 5 | org.gradle.warning.mode=fail 6 | -------------------------------------------------------------------------------- /java/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-lambda/d9668bef060627c40f39cc8215fc81ed4724a391/java/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /java/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 5 | networkTimeout=10000 6 | validateDistributionUrl=true 7 | zipStoreBase=GRADLE_USER_HOME 8 | zipStorePath=wrapper/dists 9 | -------------------------------------------------------------------------------- /java/layer-javaagent/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | } 4 | 5 | val agentClasspath by configurations.creating { 6 | extendsFrom(configurations["implementation"]) 7 | isCanBeConsumed = false 8 | isCanBeResolved = true 9 | attributes { 10 | attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling::class.java, Bundling.SHADOWED)) 11 | } 12 | } 13 | 14 | dependencies { 15 | // version set in dependencyManagement/build.gradle.kts 16 | implementation("io.opentelemetry.javaagent", "opentelemetry-javaagent") 17 | } 18 | 19 | tasks { 20 | val createLayer by registering(Zip::class) { 21 | archiveFileName.set("opentelemetry-javaagent-layer.zip") 22 | destinationDirectory.set(file("$buildDir/distributions")) 23 | 24 | from(agentClasspath) { 25 | rename(".*.jar", "opentelemetry-javaagent.jar") 26 | } 27 | 28 | from("scripts") 29 | } 30 | 31 | named("assemble") { 32 | dependsOn(createLayer) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /java/layer-javaagent/scripts/otel-handler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ef -o pipefail 4 | 5 | export JAVA_TOOL_OPTIONS="-javaagent:/opt/opentelemetry-javaagent.jar ${JAVA_TOOL_OPTIONS}" 6 | 7 | if [[ $OTEL_RESOURCE_ATTRIBUTES != *"service.name="* ]]; then 8 | export OTEL_RESOURCE_ATTRIBUTES="service.name=${AWS_LAMBDA_FUNCTION_NAME},${OTEL_RESOURCE_ATTRIBUTES}" 9 | fi 10 | 11 | if [[ -z "$OTEL_PROPAGATORS" ]]; then 12 | export OTEL_PROPAGATORS="tracecontext,baggage,xray" 13 | fi 14 | 15 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT=10000 16 | 17 | ######################################## 18 | 19 | ARGS=("$@") 20 | EXTRA_ARGS=() 21 | 22 | if [ "${OTEL_JAVA_AGENT_FAST_STARTUP_ENABLED}" == "true" ]; then 23 | echo "[OTEL] Enabling fast startup mode ..." 24 | # Disable bytecode verification 25 | EXTRA_ARGS+=("-Xverify:none") 26 | # Be sure that tiered compilation is enabled 27 | EXTRA_ARGS+=("-XX:+TieredCompilation") 28 | # Stop tiered compilation at level 1 29 | EXTRA_ARGS+=("-XX:TieredStopAtLevel=1") 30 | for i in "${!ARGS[@]}"; do 31 | # If tiered compilation is disabled, ignore it as we enable it at level 1 for fast startup 32 | if [[ ${ARGS[i]} = "-XX:-TieredCompilation" ]]; then 33 | unset 'ARGS[i]' 34 | fi 35 | done 36 | fi 37 | 38 | ARGS=("${ARGS[0]}" "${EXTRA_ARGS[@]}" "${ARGS[@]:1}") 39 | 40 | exec "${ARGS[@]}" 41 | -------------------------------------------------------------------------------- /java/layer-wrapper/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | } 4 | 5 | dependencies { 6 | runtimeOnly(project(":awssdk-autoconfigure")) 7 | 8 | runtimeOnly("io.opentelemetry.instrumentation:opentelemetry-aws-lambda-events-2.2") 9 | runtimeOnly("io.opentelemetry:opentelemetry-exporter-logging") 10 | runtimeOnly("io.opentelemetry:opentelemetry-exporter-otlp") 11 | runtimeOnly("io.opentelemetry:opentelemetry-extension-trace-propagators") 12 | runtimeOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") 13 | runtimeOnly("io.opentelemetry.contrib:opentelemetry-aws-resources") 14 | } 15 | 16 | tasks { 17 | val createLayer by registering(Zip::class) { 18 | archiveFileName.set("opentelemetry-javawrapper-layer.zip") 19 | destinationDirectory.set(file("$buildDir/distributions")) 20 | 21 | from(configurations["runtimeClasspath"]) { 22 | into("java/lib") 23 | } 24 | 25 | // Can be used by redistributions of the wrapper to add more libraries. 26 | from("build/extensions") { 27 | into("java/lib") 28 | } 29 | 30 | from("scripts") 31 | } 32 | 33 | named("assemble") { 34 | dependsOn(createLayer) 35 | } 36 | } 37 | 38 | tasks.register("printOtelJavaInstrumentationVersion") { 39 | doLast { 40 | println(project.configurations["runtimeClasspath"].resolvedConfiguration.resolvedArtifacts.find { it.name == "opentelemetry-aws-lambda-events-2.2" }?.moduleVersion?.id?.version) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /java/layer-wrapper/scripts/otel-handler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ef -o pipefail 4 | 5 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER="$_HANDLER" 6 | export _HANDLER="io.opentelemetry.instrumentation.awslambdaevents.v2_2.TracingRequestWrapper" 7 | 8 | if [[ $OTEL_RESOURCE_ATTRIBUTES != *"service.name="* ]]; then 9 | export OTEL_RESOURCE_ATTRIBUTES="service.name=${AWS_LAMBDA_FUNCTION_NAME},${OTEL_RESOURCE_ATTRIBUTES}" 10 | fi 11 | 12 | if [[ -z "$OTEL_PROPAGATORS" ]]; then 13 | export OTEL_PROPAGATORS="tracecontext,baggage,xray" 14 | fi 15 | 16 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT=10000 17 | 18 | # java17 runtime puts the handler to run as a command line argument and seems to prefer 19 | # this over _HANDLER, so apply a regex to replace the original handler name with our wrapper 20 | exec "${@//$OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER/$_HANDLER}" 21 | -------------------------------------------------------------------------------- /java/layer-wrapper/scripts/otel-proxy-handler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ef -o pipefail 4 | 5 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER="$_HANDLER" 6 | export _HANDLER="io.opentelemetry.instrumentation.awslambdaevents.v2_2.TracingRequestApiGatewayWrapper" 7 | 8 | if [[ $OTEL_RESOURCE_ATTRIBUTES != *"service.name="* ]]; then 9 | export OTEL_RESOURCE_ATTRIBUTES="service.name=${AWS_LAMBDA_FUNCTION_NAME},${OTEL_RESOURCE_ATTRIBUTES}" 10 | fi 11 | 12 | if [[ -z "$OTEL_PROPAGATORS" ]]; then 13 | export OTEL_PROPAGATORS="tracecontext,baggage,xray" 14 | fi 15 | 16 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT=10000 17 | 18 | # java17 runtime puts the handler to run as a command line argument and seems to prefer 19 | # this over _HANDLER, so apply a regex to replace the original handler name with our wrapper 20 | exec "${@//$OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER/$_HANDLER}" 21 | -------------------------------------------------------------------------------- /java/layer-wrapper/scripts/otel-sqs-handler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ef -o pipefail 4 | 5 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER="$_HANDLER" 6 | export _HANDLER="io.opentelemetry.instrumentation.awslambdaevents.v2_2.TracingSqsEventWrapper" 7 | 8 | if [[ $OTEL_RESOURCE_ATTRIBUTES != *"service.name="* ]]; then 9 | export OTEL_RESOURCE_ATTRIBUTES="service.name=${AWS_LAMBDA_FUNCTION_NAME},${OTEL_RESOURCE_ATTRIBUTES}" 10 | fi 11 | 12 | if [[ -z "$OTEL_PROPAGATORS" ]]; then 13 | export OTEL_PROPAGATORS="tracecontext,baggage,xray" 14 | fi 15 | 16 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT=10000 17 | 18 | # java17 runtime puts the handler to run as a command line argument and seems to prefer 19 | # this over _HANDLER, so apply a regex to replace the original handler name with our wrapper 20 | exec "${@//$OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER/$_HANDLER}" 21 | -------------------------------------------------------------------------------- /java/layer-wrapper/scripts/otel-stream-handler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ef -o pipefail 4 | 5 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER="$_HANDLER" 6 | export _HANDLER="io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestStreamWrapper" 7 | 8 | if [[ $OTEL_RESOURCE_ATTRIBUTES != *"service.name="* ]]; then 9 | export OTEL_RESOURCE_ATTRIBUTES="service.name=${AWS_LAMBDA_FUNCTION_NAME},${OTEL_RESOURCE_ATTRIBUTES}" 10 | fi 11 | 12 | if [[ -z "$OTEL_PROPAGATORS" ]]; then 13 | export OTEL_PROPAGATORS="tracecontext,baggage,xray" 14 | fi 15 | 16 | export OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT=10000 17 | 18 | # java17 runtime puts the handler to run as a command line argument and seems to prefer 19 | # this over _HANDLER, so apply a regex to replace the original handler name with our wrapper 20 | exec "${@//$OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER/$_HANDLER}" 21 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/README.md: -------------------------------------------------------------------------------- 1 | # AWS SDK Sample App 2 | 3 | This application makes a simple request to `S3.ListBuckets` using the AWS SDK v2. You can find 4 | deployment scripts using Terraform that are configured to deploy this sample app to AWS Lambda and 5 | API Gateway while publishing and using the OpenTelemetry layers. 6 | 7 | ## Requirements 8 | 9 | - Java for building this repository 10 | - [Terraform](https://www.terraform.io/downloads.html) 11 | - AWS credentials, either using environment variables or via the CLI and `aws configure` 12 | 13 | First, in the `java` subfolder of this repository, build all the artifacts. 14 | 15 | ``` 16 | ./gradlew build 17 | ``` 18 | 19 | Then, decide if you want to try the wrapper or the agent version. Navigate to the appropriate 20 | subfolder of [deploy](./deploy) and deploy with Terraform. 21 | 22 | ``` 23 | terraform init 24 | terraform apply 25 | ``` 26 | 27 | Use the following command to configure runtime and architecture 28 | 29 | ``` 30 | TF_VAR_architecture=x86_64 \ 31 | TF_VAR_runtime=java11 \ 32 | terraform apply -auto-approve 33 | ``` 34 | 35 | For the agent version, to change the configuration of the OpenTelemetry collector, you can provide the ARN of a Lambda layer with a custom collector configuration in a file named `config.yaml` when prompted after running the `terraform apply` command. 36 | 37 | After deployment, a URL which can be used to invoke the function via API Gateway will be displayed. The agent version 38 | tends to take 10-20s for the first request, while the wrapper version tends to take 5-10s. Confirm 39 | that spans are logged in the CloudWatch logs for the function on the AWS Console either for the 40 | [wrapper](https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/$252Faws$252Flambda$252Fhello-awssdk-java-wrapper) 41 | or for the [agent](https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/$252Faws$252Flambda$252Fhello-awssdk-javaagent). 42 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("com.github.johnrengelman.shadow") 4 | } 5 | 6 | dependencies { 7 | implementation("io.opentelemetry:opentelemetry-api") 8 | implementation("com.amazonaws:aws-lambda-java-core") 9 | implementation("com.amazonaws:aws-lambda-java-events") 10 | implementation("org.apache.logging.log4j:log4j-core") 11 | implementation("software.amazon.awssdk:s3") 12 | 13 | runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl") 14 | } 15 | 16 | tasks { 17 | assemble { 18 | dependsOn("shadowJar") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/deploy/agent/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "io.opentelemetry.lambda.sampleapps.awssdk.AwsSdkRequestHandler::handleRequest" 8 | runtime = var.runtime 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../build/libs/aws-sdk-all.jar" 12 | 13 | memory_size = 512 14 | timeout = 120 15 | publish = true 16 | 17 | layers = compact([ 18 | var.collector_layer_arn, 19 | var.sdk_layer_arn, 20 | var.collector_config_layer_arn, 21 | ]) 22 | 23 | environment_variables = (var.collector_config_layer_arn == null ? 24 | { 25 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-handler", 26 | OTEL_METRICS_EXPORTER = "otlp", 27 | } : 28 | { 29 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-handler", 30 | OTEL_METRICS_EXPORTER = "otlp", 31 | OPENTELEMETRY_COLLECTOR_CONFIG_URI = "/opt/config.yaml" 32 | }) 33 | 34 | tracing_mode = var.tracing_mode 35 | 36 | attach_policy_statements = true 37 | policy_statements = { 38 | s3 = { 39 | effect = "Allow" 40 | actions = [ 41 | "s3:ListAllMyBuckets" 42 | ] 43 | resources = [ 44 | "*" 45 | ] 46 | } 47 | } 48 | } 49 | 50 | resource "aws_lambda_alias" "provisioned" { 51 | name = "provisioned" 52 | function_name = module.hello-lambda-function.lambda_function_name 53 | function_version = module.hello-lambda-function.lambda_function_version 54 | } 55 | 56 | resource "aws_lambda_provisioned_concurrency_config" "lambda_api" { 57 | function_name = aws_lambda_alias.provisioned.function_name 58 | provisioned_concurrent_executions = 2 59 | qualifier = aws_lambda_alias.provisioned.name 60 | } 61 | 62 | module "api-gateway" { 63 | source = "../../../../../utils/terraform/api-gateway-proxy" 64 | 65 | name = var.name 66 | function_name = aws_lambda_alias.provisioned.function_name 67 | function_qualifier = aws_lambda_alias.provisioned.name 68 | function_invoke_arn = aws_lambda_alias.provisioned.invoke_arn 69 | enable_xray_tracing = var.tracing_mode == "Active" 70 | } 71 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/deploy/agent/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api-gateway-url" { 2 | value = module.api-gateway.api_gateway_url 3 | } 4 | 5 | output "function_role_name" { 6 | value = module.hello-lambda-function.lambda_role_name 7 | } 8 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/deploy/agent/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-java-awssdk-agent" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | // TODO(anuraaga): Add default when a public layer is published. 11 | } 12 | 13 | variable "collector_config_layer_arn" { 14 | type = string 15 | description = "ARN for the Lambda layer containing the OpenTelemetry collector configuration file" 16 | } 17 | 18 | variable "sdk_layer_arn" { 19 | type = string 20 | description = "ARN for the Lambda layer containing the OpenTelemetry Java Agent" 21 | // TODO(anuraaga): Add default when a public layer is published. 22 | } 23 | 24 | variable "tracing_mode" { 25 | type = string 26 | description = "Lambda function tracing mode" 27 | default = "PassThrough" 28 | } 29 | 30 | variable "architecture" { 31 | type = string 32 | description = "Lambda function architecture, valid values are arm64 or x86_64" 33 | default = "x86_64" 34 | } 35 | 36 | variable "runtime" { 37 | type = string 38 | description = "java agent runtime used for sample Lambda Function" 39 | default = "java11" 40 | } 41 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/deploy/wrapper/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "io.opentelemetry.lambda.sampleapps.awssdk.AwsSdkRequestHandler::handleRequest" 8 | runtime = var.runtime 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../build/libs/aws-sdk-all.jar" 12 | 13 | memory_size = 384 14 | timeout = 20 15 | 16 | layers = compact([ 17 | var.collector_layer_arn, 18 | var.sdk_layer_arn 19 | ]) 20 | 21 | environment_variables = { 22 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-proxy-handler" 23 | } 24 | 25 | tracing_mode = var.tracing_mode 26 | 27 | attach_policy_statements = true 28 | policy_statements = { 29 | s3 = { 30 | effect = "Allow" 31 | actions = [ 32 | "s3:ListAllMyBuckets" 33 | ] 34 | resources = [ 35 | "*" 36 | ] 37 | } 38 | } 39 | } 40 | 41 | module "api-gateway" { 42 | source = "../../../../../utils/terraform/api-gateway-proxy" 43 | 44 | name = var.name 45 | function_name = module.hello-lambda-function.lambda_function_name 46 | function_invoke_arn = module.hello-lambda-function.lambda_function_invoke_arn 47 | enable_xray_tracing = var.tracing_mode == "Active" 48 | } 49 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/deploy/wrapper/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api-gateway-url" { 2 | value = module.api-gateway.api_gateway_url 3 | } 4 | 5 | output "function_role_name" { 6 | value = module.hello-lambda-function.lambda_role_name 7 | } 8 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/deploy/wrapper/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-java-awssdk-wrapper" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | // TODO(anuraaga): Add default when a public layer is published. 11 | } 12 | 13 | variable "sdk_layer_arn" { 14 | type = string 15 | description = "ARN for the Lambda layer containing the OpenTelemetry Java Wrapper" 16 | // TODO(anuraaga): Add default when a public layer is published. 17 | } 18 | 19 | variable "tracing_mode" { 20 | type = string 21 | description = "Lambda function tracing mode" 22 | default = "PassThrough" 23 | } 24 | 25 | variable "architecture" { 26 | type = string 27 | description = "Lambda function architecture, valid values are arm64 or x86_64" 28 | default = "x86_64" 29 | } 30 | 31 | variable "runtime" { 32 | type = string 33 | description = "java wrapper runtime used for sample Lambda Function" 34 | default = "java11" 35 | } 36 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/src/main/java/io/opentelemetry/lambda/sampleapps/awssdk/AwsSdkRequestHandler.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.lambda.sampleapps.awssdk; 2 | 3 | import com.amazonaws.services.lambda.runtime.Context; 4 | import com.amazonaws.services.lambda.runtime.RequestHandler; 5 | import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; 6 | import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; 7 | import io.opentelemetry.api.GlobalOpenTelemetry; 8 | import io.opentelemetry.api.common.AttributeKey; 9 | import io.opentelemetry.api.common.Attributes; 10 | import io.opentelemetry.api.metrics.LongUpDownCounter; 11 | import io.opentelemetry.api.metrics.Meter; 12 | import org.apache.logging.log4j.LogManager; 13 | import org.apache.logging.log4j.Logger; 14 | import software.amazon.awssdk.services.s3.S3Client; 15 | import software.amazon.awssdk.services.s3.model.ListBucketsResponse; 16 | 17 | public class AwsSdkRequestHandler 18 | implements RequestHandler { 19 | 20 | private static final Logger logger = LogManager.getLogger(AwsSdkRequestHandler.class); 21 | private static final Meter sampleMeter = 22 | GlobalOpenTelemetry.getMeterProvider() 23 | .meterBuilder("aws-otel") 24 | .setInstrumentationVersion("1.0") 25 | .build(); 26 | private static final LongUpDownCounter queueSizeCounter = 27 | sampleMeter 28 | .upDownCounterBuilder("queueSizeChange") 29 | .setDescription("Queue Size change") 30 | .setUnit("one") 31 | .build(); 32 | 33 | private static final AttributeKey API_NAME = AttributeKey.stringKey("apiName"); 34 | private static final AttributeKey STATUS_CODE = AttributeKey.stringKey("statuscode"); 35 | private static final Attributes METRIC_ATTRIBUTES = 36 | Attributes.builder().put(API_NAME, "apiName").put(STATUS_CODE, "200").build(); 37 | 38 | @Override 39 | public APIGatewayProxyResponseEvent handleRequest( 40 | APIGatewayProxyRequestEvent input, Context context) { 41 | logger.info("Serving lambda request."); 42 | 43 | APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); 44 | try (S3Client s3 = S3Client.create()) { 45 | ListBucketsResponse listBucketsResponse = s3.listBuckets(); 46 | response.setBody( 47 | "Hello lambda - found " + listBucketsResponse.buckets().size() + " buckets."); 48 | } 49 | 50 | // Generate a sample counter metric using the OpenTelemetry Java Metrics API 51 | queueSizeCounter.add(2, METRIC_ATTRIBUTES); 52 | 53 | return response; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /java/sample-apps/aws-sdk/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /java/sample-apps/okhttp/README.md: -------------------------------------------------------------------------------- 1 | # OkHttp Sample App 2 | 3 | This application makes a simple request to `https://aws.amazon.com` using OkHttp. You can find 4 | deployment scripts using Terraform that are configured to deploy this sample app to AWS Lambda and 5 | API Gateway while publishing and using the OpenTelemetry layers. 6 | 7 | Notice that we initialize the library instrumentation for OkHttp provided by the 8 | `io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0` artifact using our own code, 9 | 10 | ```java 11 | OkHttpClient client = 12 | new OkHttpClient.Builder() 13 | .addInterceptor(OkHttpTracing.create(GlobalOpenTelemetry.get()).newInterceptor()) 14 | .build(); 15 | ``` 16 | 17 | This is to allow the application to be deployed with the wrapper and still trace the OkHttp client. 18 | If using the agent, this is unnecessary. 19 | 20 | ## Requirements 21 | 22 | - Java for building this repository 23 | - [Terraform](https://www.terraform.io/downloads.html) 24 | - AWS credentials, either using environment variables or via the CLI and `aws configure` 25 | 26 | First, in the `java` subfolder of this repository, build all the artifacts. 27 | 28 | ``` 29 | ./gradlew build 30 | ``` 31 | 32 | Then, navigate to [deploy/wrapper](./deploy/wrapper) and deploy with Terraform. 33 | 34 | ``` 35 | terraform init 36 | terraform apply 37 | ``` 38 | 39 | Use the following command to configure runtime and architecture 40 | 41 | ``` 42 | TF_VAR_architecture=x86_64 \ 43 | TF_VAR_runtime=java11 \ 44 | terraform apply -auto-approve 45 | ``` 46 | 47 | After deployment, a URL which can be used to invoke the function via API Gateway will be displayed. As it uses the 48 | wrapper, it tends to take 5-10s. Confirm that spans are logged in the CloudWatch logs for the function on the AWS Console for the 49 | [wrapper](https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/$252Faws$252Flambda$252Fhello-awssdk-java-wrapper).n 50 | 51 | Note that this example cannot currently be used with the agent because it does not behave correctly 52 | with applications that manually initialize library instrumentation. This issue will be fixed in a 53 | future version. 54 | -------------------------------------------------------------------------------- /java/sample-apps/okhttp/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("com.github.johnrengelman.shadow") 4 | } 5 | 6 | dependencies { 7 | implementation("com.amazonaws:aws-lambda-java-core") 8 | implementation("com.amazonaws:aws-lambda-java-events") 9 | implementation("com.squareup.okhttp3:okhttp") 10 | implementation("io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0") 11 | implementation("org.apache.logging.log4j:log4j-core") 12 | 13 | runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl") 14 | } 15 | 16 | tasks { 17 | assemble { 18 | dependsOn("shadowJar") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /java/sample-apps/okhttp/deploy/wrapper/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "io.opentelemetry.lambda.sampleapps.okhttp.OkHttpRequestHandler::handleRequest" 8 | runtime = var.runtime 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../build/libs/okhttp-all.jar" 12 | 13 | memory_size = 384 14 | timeout = 20 15 | 16 | layers = compact([ 17 | var.collector_layer_arn, 18 | var.sdk_layer_arn 19 | ]) 20 | 21 | environment_variables = { 22 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-proxy-handler" 23 | } 24 | 25 | tracing_mode = var.tracing_mode 26 | 27 | attach_policy_statements = true 28 | policy_statements = { 29 | s3 = { 30 | effect = "Allow" 31 | actions = [ 32 | "s3:ListAllMyBuckets" 33 | ] 34 | resources = [ 35 | "*" 36 | ] 37 | } 38 | } 39 | } 40 | 41 | module "api-gateway" { 42 | source = "../../../../../utils/terraform/api-gateway-proxy" 43 | 44 | name = var.name 45 | function_name = module.hello-lambda-function.lambda_function_name 46 | function_invoke_arn = module.hello-lambda-function.lambda_function_invoke_arn 47 | enable_xray_tracing = var.tracing_mode == "Active" 48 | } 49 | -------------------------------------------------------------------------------- /java/sample-apps/okhttp/deploy/wrapper/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api-gateway-url" { 2 | value = module.api-gateway.api_gateway_url 3 | } 4 | 5 | output "function_role_name" { 6 | value = module.hello-lambda-function.lambda_role_name 7 | } 8 | -------------------------------------------------------------------------------- /java/sample-apps/okhttp/deploy/wrapper/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-java-okhttp-wrapper" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | // TODO(anuraaga): Add default when a public layer is published. 11 | } 12 | 13 | variable "sdk_layer_arn" { 14 | type = string 15 | description = "ARN for the Lambda layer containing the OpenTelemetry Java Wrapper" 16 | // TODO(anuraaga): Add default when a public layer is published. 17 | } 18 | 19 | variable "tracing_mode" { 20 | type = string 21 | description = "Lambda function tracing mode" 22 | default = "PassThrough" 23 | } 24 | 25 | variable "architecture" { 26 | type = string 27 | description = "Lambda function architecture, valid values are arm64 or x86_64" 28 | default = "x86_64" 29 | } 30 | 31 | variable "runtime" { 32 | type = string 33 | description = "java runtime used for sample Lambda Function" 34 | default = "java11" 35 | } 36 | -------------------------------------------------------------------------------- /java/sample-apps/okhttp/src/main/java/io/opentelemetry/lambda/sampleapps/okhttp/OkHttpRequestHandler.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.lambda.sampleapps.okhttp; 2 | 3 | import com.amazonaws.services.lambda.runtime.Context; 4 | import com.amazonaws.services.lambda.runtime.RequestHandler; 5 | import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; 6 | import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; 7 | import io.opentelemetry.api.GlobalOpenTelemetry; 8 | import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry; 9 | import java.io.IOException; 10 | import java.io.UncheckedIOException; 11 | import okhttp3.Call; 12 | import okhttp3.OkHttpClient; 13 | import okhttp3.Request; 14 | import okhttp3.Response; 15 | import org.apache.logging.log4j.LogManager; 16 | import org.apache.logging.log4j.Logger; 17 | 18 | public class OkHttpRequestHandler 19 | implements RequestHandler { 20 | 21 | private static final Logger logger = LogManager.getLogger(OkHttpRequestHandler.class); 22 | 23 | @Override 24 | public APIGatewayProxyResponseEvent handleRequest( 25 | APIGatewayProxyRequestEvent input, Context context) { 26 | logger.info("Serving lambda request."); 27 | 28 | OkHttpClient baseClient = new OkHttpClient(); 29 | Call.Factory callFactory = 30 | OkHttpTelemetry.create(GlobalOpenTelemetry.get()).newCallFactory(baseClient); 31 | 32 | APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); 33 | 34 | Request request = new Request.Builder().url("https://aws.amazon.com/").build(); 35 | try (Response okhttpResponse = callFactory.newCall(request).execute()) { 36 | response.setBody( 37 | "Hello lambda - fetched " + okhttpResponse.body().string().length() + " bytes."); 38 | } catch (IOException e) { 39 | throw new UncheckedIOException("Could not fetch with okhttp", e); 40 | } 41 | return response; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /java/sample-apps/okhttp/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/README.md: -------------------------------------------------------------------------------- 1 | # Amazon SQS Sample App 2 | 3 | This application includes a Lambda with an SQS queue as an event source. You can find 4 | deployment scripts using Terraform that are configured to deploy this sample app to AWS Lambda while publishing and using the OpenTelemetry layers. 5 | 6 | ## Requirements 7 | 8 | - Java for building this repository 9 | - [Terraform](https://www.terraform.io/downloads.html) 10 | - AWS credentials, either using environment variables or via the CLI and `aws configure` 11 | 12 | First, in the `java` subfolder of this repository, build all the artifacts. 13 | 14 | ``` 15 | ./gradlew build 16 | ``` 17 | 18 | Then, decide if you want to try the wrapper or the agent version. Navigate to the appropriate 19 | subfolder of [deploy](./deploy) and deploy with Terraform. 20 | 21 | ``` 22 | terraform init 23 | terraform apply 24 | ``` 25 | 26 | Use the following command to configure runtime and architecture 27 | 28 | ``` 29 | TF_VAR_architecture=x86_64 \ 30 | TF_VAR_runtime=java11 \ 31 | terraform apply -auto-approve 32 | ``` 33 | 34 | For the agent version, to change the configuration of the OpenTelemetry collector, you can provide the ARN of a Lambda layer with a custom collector configuration in a file named `config.yaml` when prompted after running the `terraform apply` command. 35 | 36 | After deployment, login to AWS and test the Lambda function using the predefined SQS test payload. The agent version tends to take 10-20s for the first request, while the wrapper version tends to take 5-10s. Confirm 37 | that spans are logged in the CloudWatch logs for the function on the AWS Console either for the 38 | [wrapper](https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/$252Faws$252Flambda$252Fhello-awssdk-java-wrapper) 39 | or for the [agent](https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logsV2:log-groups/log-group/$252Faws$252Flambda$252Fhello-awssdk-javaagent). 40 | 41 | If you already have an SQS queue to test with, uncomment the commented sections at the bottom of the `main.tf` and `variables.tf` files and then provide the ARN for your queue when running `terraform apply`. You will then need to publish a message to the queue to test the Lambda function. 42 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("com.github.johnrengelman.shadow") 4 | } 5 | 6 | dependencies { 7 | implementation("com.amazonaws:aws-lambda-java-core") 8 | implementation("com.amazonaws:aws-lambda-java-events") 9 | implementation("org.apache.logging.log4j:log4j-core") 10 | 11 | runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl") 12 | } 13 | 14 | tasks { 15 | assemble { 16 | dependsOn("shadowJar") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/deploy/agent/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "io.opentelemetry.lambda.sampleapps.sqs.SqsRequestHandler::handleRequest" 8 | runtime = var.runtime 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../build/libs/sqs-all.jar" 12 | 13 | memory_size = 512 14 | timeout = 120 15 | publish = true 16 | 17 | layers = compact([ 18 | var.collector_layer_arn, 19 | var.sdk_layer_arn, 20 | var.collector_config_layer_arn, 21 | ]) 22 | 23 | environment_variables = (var.collector_config_layer_arn == null ? 24 | { 25 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-handler", 26 | OTEL_METRICS_EXPORTER = "otlp", 27 | } : 28 | { 29 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-handler", 30 | OTEL_METRICS_EXPORTER = "otlp", 31 | OPENTELEMETRY_COLLECTOR_CONFIG_URI = "/opt/config.yaml" 32 | }) 33 | 34 | tracing_mode = var.tracing_mode 35 | 36 | # UNCOMMENT BELOW TO TEST WITH YOUR SQS QUEUE 37 | # policy_statements = { 38 | # sqs_read = { 39 | # effect = "Allow", 40 | # actions = ["sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes"] 41 | # resources = [var.sqs_queue_arn] 42 | # } 43 | # } 44 | 45 | # event_source_mapping = { 46 | # sqs_queue = { 47 | # event_source_arn = var.sqs_queue_arn 48 | # } 49 | # } 50 | 51 | # allowed_triggers = { 52 | # sqs_queue = { 53 | # principal = "sqs.amazonaws.com" 54 | # source_arn = "${var.sqs_queue_arn}" 55 | # } 56 | # } 57 | } 58 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/deploy/agent/outputs.tf: -------------------------------------------------------------------------------- 1 | output "function_role_name" { 2 | value = module.hello-lambda-function.lambda_role_name 3 | } 4 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/deploy/agent/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-java-awssdk-agent" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | // TODO(anuraaga): Add default when a public layer is published. 11 | } 12 | 13 | variable "collector_config_layer_arn" { 14 | type = string 15 | description = "ARN for the Lambda layer containing the OpenTelemetry collector configuration file" 16 | } 17 | 18 | variable "sdk_layer_arn" { 19 | type = string 20 | description = "ARN for the Lambda layer containing the OpenTelemetry Java Agent" 21 | // TODO(anuraaga): Add default when a public layer is published. 22 | } 23 | 24 | variable "tracing_mode" { 25 | type = string 26 | description = "Lambda function tracing mode" 27 | default = "PassThrough" 28 | } 29 | 30 | variable "architecture" { 31 | type = string 32 | description = "Lambda function architecture, valid values are arm64 or x86_64" 33 | default = "x86_64" 34 | } 35 | 36 | # UNCOMMENT BELOW TO TEST WITH YOUR SQS QUEUE 37 | # variable "sqs_queue_arn" { 38 | # type = string 39 | # description = "ARN for the SQS queue to use an event source for the Lambda" 40 | # } 41 | 42 | variable "runtime" { 43 | type = string 44 | description = "java runtime used for sample Lambda Function" 45 | default = "java11" 46 | } 47 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/deploy/wrapper/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "io.opentelemetry.lambda.sampleapps.sqs.SqsRequestHandler::handleRequest" 8 | runtime = var.runtime 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../build/libs/sqs-all.jar" 12 | 13 | memory_size = 384 14 | timeout = 20 15 | 16 | layers = compact([ 17 | var.collector_layer_arn, 18 | var.sdk_layer_arn 19 | ]) 20 | 21 | environment_variables = { 22 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-sqs-handler" 23 | } 24 | 25 | tracing_mode = var.tracing_mode 26 | 27 | # UNCOMMENT BELOW TO TEST WITH YOUR SQS QUEUE 28 | # policy_statements = { 29 | # sqs_read = { 30 | # effect = "Allow", 31 | # actions = ["sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes"] 32 | # resources = [var.sqs_queue_arn] 33 | # } 34 | # } 35 | 36 | # event_source_mapping = { 37 | # sqs_queue = { 38 | # event_source_arn = var.sqs_queue_arn 39 | # } 40 | # } 41 | 42 | # allowed_triggers = { 43 | # sqs_queue = { 44 | # principal = "sqs.amazonaws.com" 45 | # source_arn = "${var.sqs_queue_arn}" 46 | # } 47 | # } 48 | } 49 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/deploy/wrapper/outputs.tf: -------------------------------------------------------------------------------- 1 | output "function_role_name" { 2 | value = module.hello-lambda-function.lambda_role_name 3 | } 4 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/deploy/wrapper/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-java-awssdk-wrapper" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | // TODO(anuraaga): Add default when a public layer is published. 11 | } 12 | 13 | variable "sdk_layer_arn" { 14 | type = string 15 | description = "ARN for the Lambda layer containing the OpenTelemetry Java Wrapper" 16 | // TODO(anuraaga): Add default when a public layer is published. 17 | } 18 | 19 | variable "tracing_mode" { 20 | type = string 21 | description = "Lambda function tracing mode" 22 | default = "PassThrough" 23 | } 24 | 25 | variable "architecture" { 26 | type = string 27 | description = "Lambda function architecture, valid values are arm64 or x86_64" 28 | default = "x86_64" 29 | } 30 | 31 | # UNCOMMENT BELOW TO TEST WITH YOUR SQS QUEUE 32 | # variable "sqs_queue_arn" { 33 | # type = string 34 | # description = "ARN for the SQS queue to use an event source for the Lambda" 35 | # } 36 | 37 | variable "runtime" { 38 | type = string 39 | description = "java runtime used for sample Lambda Function" 40 | default = "java11" 41 | } 42 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/src/main/java/io/opentelemetry/lambda/sampleapps/sqs/SqsRequestHandler.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.lambda.sampleapps.sqs; 2 | 3 | import com.amazonaws.services.lambda.runtime.Context; 4 | import com.amazonaws.services.lambda.runtime.RequestHandler; 5 | import com.amazonaws.services.lambda.runtime.events.SQSEvent; 6 | import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage; 7 | import org.apache.logging.log4j.LogManager; 8 | import org.apache.logging.log4j.Logger; 9 | 10 | public class SqsRequestHandler implements RequestHandler { 11 | 12 | private static final Logger logger = LogManager.getLogger(SqsRequestHandler.class); 13 | 14 | @Override 15 | public Void handleRequest(SQSEvent event, Context context) { 16 | logger.info("Processing message(s) from SQS"); 17 | 18 | for (SQSMessage msg : event.getRecords()) { 19 | logger.info("SOURCE QUEUE: " + msg.getEventSourceArn()); 20 | logger.info("MESSAGE: " + msg.getBody()); 21 | } 22 | 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /java/sample-apps/sqs/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /java/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | plugins { 3 | id("com.diffplug.spotless") version "7.0.4" 4 | id("com.github.ben-manes.versions") version "0.52.0" 5 | id("com.github.johnrengelman.shadow") version "8.1.1" 6 | } 7 | } 8 | 9 | dependencyResolutionManagement { 10 | repositories { 11 | mavenCentral() 12 | mavenLocal() 13 | } 14 | } 15 | 16 | include(":awssdk-autoconfigure") 17 | include(":dependencyManagement") 18 | include(":layer-javaagent") 19 | include(":layer-wrapper") 20 | include(":sample-apps:aws-sdk") 21 | include(":sample-apps:okhttp") 22 | include(":sample-apps:sqs") 23 | 24 | rootProject.name = "opentelemetry-lambda-java" 25 | -------------------------------------------------------------------------------- /nodejs/.commitlintrc.yml: -------------------------------------------------------------------------------- 1 | extends: 2 | - '@commitlint/config-conventional' 3 | rules: 4 | header-max-length: [1, 'always', 72] 5 | type-enum: 6 | - 2 7 | - always 8 | - - ci 9 | - feat 10 | - fix 11 | - docs 12 | - style 13 | - refactor 14 | - perf 15 | - test 16 | - revert 17 | - chore 18 | help: | 19 | **Possible types**: 20 | `ci`: Changes to our CI configuration files and scripts (example scopes: Travis, Circle CI, BrowserStack, SauceLabs) 21 | `feat`: Adds a new feature. 22 | `fix`: Solves a bug. 23 | `docs`: Adds or alters documentation. (example scopes: readme, worker, code_of_conduct, contributors) 24 | `style`: Improves formatting, white-space. 25 | `refactor`: Rewrites code without feature, performance or bug changes. 26 | `perf`: Improves performance. 27 | `test`: Adds or modifies tests. (example scopes: functionals, unit-tests) 28 | `revert`: Changes that reverting other changes 29 | `chore`: No production code change. Updating grunt tasks etc; 30 | -------------------------------------------------------------------------------- /nodejs/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /nodejs/.gitattributes: -------------------------------------------------------------------------------- 1 | ## This .gitattributes file automatically formats the EOL character in certain filetypes within the repository 2 | 3 | ## Source code 4 | # JavaScript, TypeScript, c, and h source files 5 | *.js text eol=lf 6 | *.ts text eol=lf 7 | *.h text eol=lf diff=cpp 8 | *.c text eol=lf diff=cpp 9 | 10 | # Shell scripts 11 | *.sh text eol=lf 12 | *.bash text eol=lf 13 | 14 | # Windows batch and PowerShell scripts 15 | *.bat text eol=crlf 16 | *.cmd text eol=crlf 17 | *.ps1 text eol=crlf 18 | 19 | ##### Other file types ##### 20 | 21 | ## Text files and documentation 22 | *.txt text 23 | README* text 24 | RELEASING* text 25 | CHANGELOG* text 26 | CONTRIBUTING* text 27 | INSTALL* text 28 | LICENSE* text 29 | 30 | ## Non-text documentation 31 | *.html text diff=html 32 | *.pdf binary 33 | *.json text 34 | *.rtf binary 35 | 36 | ## Git Properties 37 | .gitignore text 38 | .gitmodules text 39 | .gitattributes text 40 | -------------------------------------------------------------------------------- /nodejs/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # Bower dependency directory (https://bower.io/) 24 | bower_components 25 | 26 | # node-waf configuration 27 | .lock-wscript 28 | 29 | # Compiled binary addons (https://nodejs.org/api/addons.html) 30 | build/Release 31 | 32 | # Dependency directories 33 | node_modules/ 34 | jspm_packages/ 35 | build/ 36 | 37 | # TypeScript v1 declaration files 38 | typings/ 39 | 40 | # Optional npm cache directory 41 | .npm 42 | 43 | # Optional eslint cache 44 | .eslintcache 45 | 46 | # Optional REPL history 47 | .node_repl_history 48 | 49 | # Output of 'npm pack' 50 | *.tgz 51 | 52 | # Yarn Integrity file 53 | .yarn-integrity 54 | 55 | # dotenv environment variables file 56 | .env 57 | 58 | # next.js build output 59 | .next 60 | 61 | # docs files 62 | docs 63 | 64 | .nyc_output 65 | 66 | #lerna 67 | .changelog 68 | package.json.lerna_backup 69 | 70 | # OS generated files 71 | .DS_Store 72 | 73 | # VsCode configs 74 | .vscode/ 75 | 76 | *.iml 77 | .idea 78 | -------------------------------------------------------------------------------- /nodejs/.npmignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /coverage 3 | /doc 4 | /test 5 | -------------------------------------------------------------------------------- /nodejs/eslint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | "@typescript-eslint", 4 | "header" 5 | ], 6 | extends: [ 7 | "../../node_modules/gts", 8 | ], 9 | parser: "@typescript-eslint/parser", 10 | parserOptions: { 11 | "project": "./tsconfig.json" 12 | }, 13 | rules: { 14 | "@typescript-eslint/no-this-alias": "off", 15 | "eqeqeq": "off", 16 | "prefer-rest-params": "off", 17 | "@typescript-eslint/naming-convention": [ 18 | "error", 19 | { 20 | "selector": "memberLike", 21 | "modifiers": ["private", "protected"], 22 | "format": ["camelCase"], 23 | "leadingUnderscore": "require" 24 | } 25 | ], 26 | "@typescript-eslint/no-inferrable-types": ["error", { ignoreProperties: true }], 27 | "arrow-parens": ["error", "as-needed"], 28 | "prettier/prettier": ["error", { "singleQuote": true, "arrowParens": "avoid" }], 29 | "@typescript-eslint/no-require-imports": "off", 30 | }, 31 | overrides: [ 32 | { 33 | "files": ["test/**/*.ts"], 34 | "rules": { 35 | "no-empty": "off", 36 | "@typescript-eslint/ban-ts-ignore": "off", 37 | "@typescript-eslint/no-empty-function": "off", 38 | "@typescript-eslint/no-explicit-any": "off", 39 | "@typescript-eslint/no-unused-vars": "off", 40 | "@typescript-eslint/no-var-requires": "off" 41 | } 42 | } 43 | ] 44 | }; 45 | -------------------------------------------------------------------------------- /nodejs/lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0", 3 | "changelog": { 4 | "repo": "open-telemetry/opentelemetry-lambda", 5 | "labels": { 6 | "breaking": ":boom: Breaking Change", 7 | "bug": ":bug: (Bug Fix)", 8 | "core": ":wrench: Core", 9 | "document": ":books: (Refine Doc)", 10 | "enhancement": ":rocket: (Enhancement)", 11 | "feature-request": ":sparkles: (Feature)", 12 | "internal": ":house: Internal" 13 | }, 14 | "cacheDir": ".changelog", 15 | "ignoreCommitters": ["github-actions"] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "opentelemetry-lambda", 3 | "version": "0.0.0", 4 | "private": true, 5 | "description": "This is a repository for AWS Lambda integration with OpenTelemetry.", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/open-telemetry/opentelemetry-lambda.git" 9 | }, 10 | "main": "build/src/index.js", 11 | "types": "build/src/index.d.ts", 12 | "scripts": { 13 | "build": "lerna run build", 14 | "test": "lerna run test", 15 | "lint": "lerna run lint", 16 | "lint:fix": "lerna run lint:fix" 17 | }, 18 | "workspaces": [ 19 | "packages/*", 20 | "sample-apps/*" 21 | ], 22 | "keywords": [ 23 | "opentelemetry", 24 | "nodejs", 25 | "profiling", 26 | "metrics", 27 | "stats", 28 | "plugins" 29 | ], 30 | "author": "OpenTelemetry Authors", 31 | "license": "Apache-2.0", 32 | "devDependencies": { 33 | "@typescript-eslint/eslint-plugin": "^8.29.0", 34 | "@typescript-eslint/parser": "^8.29.0", 35 | "aws-sdk": "2.1692.0", 36 | "bestzip": "2.2.1", 37 | "copyfiles": "2.4.1", 38 | "eslint": "^8.57.0", 39 | "eslint-plugin-header": "3.1.1", 40 | "eslint-plugin-import": "2.31.0", 41 | "gts": "6.0.2", 42 | "lerna": "^8.1.8", 43 | "lerna-changelog": "2.2.0", 44 | "rimraf": "6.0.1", 45 | "typescript": "5.8.3" 46 | }, 47 | "changelog": { 48 | "labels": { 49 | "breaking": ":boom: Breaking Change", 50 | "bug": ":bug: Bug Fix", 51 | "plugin-request": ":tada: New Plugins", 52 | "enhancement": ":rocket: Enhancement", 53 | "internal": ":house: Internal", 54 | "documentation": ":memo: Documentation" 55 | }, 56 | "ignoreCommitters": [ 57 | "renovate-bot", 58 | "dependabot" 59 | ] 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /nodejs/packages/layer/.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /nodejs/packages/layer/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "mocha": true, 4 | "node": true 5 | }, 6 | ...require('../../eslint.config.js') 7 | } 8 | -------------------------------------------------------------------------------- /nodejs/packages/layer/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": "ts-node/register", 3 | "spec": ["test/**/*.spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /nodejs/packages/layer/install-externals.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euf -o pipefail 4 | 5 | rm -rf ./build/workspace/node_modules 6 | 7 | # Space separated list of external NPM packages 8 | EXTERNAL_PACKAGES=( "import-in-the-middle" ) 9 | 10 | for EXTERNAL_PACKAGE in "${EXTERNAL_PACKAGES[@]}" 11 | do 12 | echo "Installing external package $EXTERNAL_PACKAGE ..." 13 | 14 | PACKAGE_VERSION=$(npm query "#$EXTERNAL_PACKAGE" \ 15 | | grep version \ 16 | | head -1 \ 17 | | awk -F: '{ print $2 }' \ 18 | | sed 's/[",]//g') 19 | 20 | echo "Resolved version of the external package $EXTERNAL_PACKAGE: $PACKAGE_VERSION" 21 | 22 | npm install "$EXTERNAL_PACKAGE@$PACKAGE_VERSION" --prefix ./build/workspace --production --ignore-scripts 23 | 24 | echo "Installed external package $EXTERNAL_PACKAGE" 25 | done 26 | -------------------------------------------------------------------------------- /nodejs/packages/layer/scripts/otel-handler: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ef -o pipefail 4 | 5 | export NODE_OPTIONS="${NODE_OPTIONS} --import /opt/init.mjs" 6 | 7 | if [[ $OTEL_RESOURCE_ATTRIBUTES != *"service.name="* ]]; then 8 | export OTEL_RESOURCE_ATTRIBUTES="service.name=${AWS_LAMBDA_FUNCTION_NAME},${OTEL_RESOURCE_ATTRIBUTES}" 9 | fi 10 | 11 | if [[ -z "$OTEL_PROPAGATORS" ]]; then 12 | export OTEL_PROPAGATORS="tracecontext,baggage,xray" 13 | fi 14 | 15 | exec "$@" 16 | -------------------------------------------------------------------------------- /nodejs/packages/layer/src/init.mjs: -------------------------------------------------------------------------------- 1 | const WRAPPER_INIT_START_TIME = Date.now(); 2 | const { default: wrapper } = await import('./wrapper.js'); 3 | await wrapper.init(); 4 | await wrapper.wrap(); 5 | console.log('OpenTelemetry wrapper init completed in', Date.now() - WRAPPER_INIT_START_TIME, 'ms'); 6 | 7 | const LOADER_INIT_START_TIME = Date.now(); 8 | await import('./loader.mjs'); 9 | console.log('OpenTelemetry loader init completed in', Date.now() - LOADER_INIT_START_TIME, 'ms'); 10 | -------------------------------------------------------------------------------- /nodejs/packages/layer/test/handler/cjs/index.js: -------------------------------------------------------------------------------- 1 | module.exports.handler = async function() { 2 | console.log("I am a CommonJS module"); 3 | return 'ok'; 4 | } 5 | -------------------------------------------------------------------------------- /nodejs/packages/layer/test/handler/cjs/index_commonjs.cjs: -------------------------------------------------------------------------------- 1 | module.exports.handler = async function() { 2 | console.log("I am a CommonJS module"); 3 | return 'ok'; 4 | } 5 | -------------------------------------------------------------------------------- /nodejs/packages/layer/test/handler/cjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-cjs-module", 3 | "version": "0.1.0", 4 | "main": "./index.js" 5 | } 6 | -------------------------------------------------------------------------------- /nodejs/packages/layer/test/handler/esm/index.js: -------------------------------------------------------------------------------- 1 | export async function handler() { 2 | console.log("I am a CommonJS module"); 3 | return 'ok'; 4 | } 5 | -------------------------------------------------------------------------------- /nodejs/packages/layer/test/handler/esm/index_esm.mjs: -------------------------------------------------------------------------------- 1 | export async function handler() { 2 | console.log("I am a ES module"); 3 | return 'ok'; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /nodejs/packages/layer/test/handler/esm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-esm-module", 3 | "version": "0.1.0", 4 | "main": "./index.js", 5 | "type": "module" 6 | } 7 | -------------------------------------------------------------------------------- /nodejs/packages/layer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "build" 6 | }, 7 | "include": [ 8 | "src/**/*.ts", 9 | "test/**/*.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /nodejs/packages/layer/tsconfig.webpack.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.esm", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "build" 6 | }, 7 | "include": [ 8 | "src/**/*.ts", 9 | "test/**/*.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /nodejs/packages/layer/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: './src/wrapper.ts', 5 | target: 'node', 6 | mode: 'production', 7 | externalsPresets: { node: true }, // in order to ignore built-in modules like path, fs, etc. 8 | externals: [ 9 | 'import-in-the-middle', 10 | '@aws-sdk', 11 | ], 12 | output: { 13 | path: path.resolve('./build/src'), 14 | filename: 'wrapper.js', 15 | library: { 16 | type: 'commonjs2', 17 | } 18 | }, 19 | resolve: { 20 | extensions: ['.ts', '.js', '.mjs'], 21 | modules: [ 22 | path.resolve('./src'), 23 | 'node_modules', 24 | ], 25 | }, 26 | module: { 27 | rules: [ 28 | { 29 | test: /\.ts$/, 30 | use: [ 31 | { 32 | loader: 'ts-loader', 33 | options: { 34 | configFile: "tsconfig.webpack.json" 35 | } 36 | } 37 | ], 38 | exclude: /node_modules/, 39 | } 40 | ], 41 | }, 42 | optimization: { 43 | minimize: true, 44 | providedExports: true, 45 | usedExports: true, 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "mocha": true, 4 | "node": true 5 | }, 6 | ...require('../../eslint.config.js') 7 | } 8 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/README.md: -------------------------------------------------------------------------------- 1 | # AWS SDK Sample Application 2 | 3 | **This Sample App is a work-in-progress because it depends on the OpenTelemetry public layer. The public layer will not be published 4 | 5 | This sample application demonstrates usage of the AWS SDK. To try it out, make sure the collector and nodejs Lambda 6 | layers are built. 7 | 8 | In [collector](../../../collector), run `make package`. 9 | In [nodejs](../../), run `npm install`. 10 | 11 | Then, run `terraform init` and `terraform apply`. The lambda function will be initialized and the URL for an API Gateway invoking the Lambda 12 | will be displayed at the end. Send a request to the URL in a browser or using curl to execute the function. Then, 13 | navigate to the function's logs [here](https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logStream:group=%252Faws%252Flambda%252Fhello-nodejs). 14 | You will see a log stream with an event time corresponding to when you issued the request - open it and you can find 15 | information about the exported spans in the log stream. 16 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/deploy/wrapper/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "index.handler" 8 | runtime = var.runtime 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../build/function.zip" 12 | 13 | memory_size = 384 14 | timeout = 20 15 | 16 | layers = compact([ 17 | var.collector_layer_arn, 18 | var.sdk_layer_arn 19 | ]) 20 | 21 | environment_variables = { 22 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-handler" 23 | OTEL_TRACES_EXPORTER = "logging" 24 | OTEL_METRICS_EXPORTER = "logging" 25 | OTEL_LOG_LEVEL = "DEBUG" 26 | OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318/" 27 | OTEL_TRACES_SAMPLER = "always_on" 28 | } 29 | 30 | tracing_mode = var.tracing_mode 31 | 32 | attach_policy_statements = true 33 | policy_statements = { 34 | s3 = { 35 | effect = "Allow" 36 | actions = [ 37 | "s3:ListAllMyBuckets" 38 | ] 39 | resources = [ 40 | "*" 41 | ] 42 | } 43 | } 44 | } 45 | 46 | module "api-gateway" { 47 | source = "../../../../../utils/terraform/api-gateway-proxy" 48 | 49 | name = var.name 50 | function_name = module.hello-lambda-function.lambda_function_name 51 | function_invoke_arn = module.hello-lambda-function.lambda_function_invoke_arn 52 | enable_xray_tracing = var.tracing_mode == "Active" 53 | } 54 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/deploy/wrapper/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api-gateway-url" { 2 | value = module.api-gateway.api_gateway_url 3 | } 4 | 5 | output "function_role_name" { 6 | value = module.hello-lambda-function.lambda_role_name 7 | } 8 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/deploy/wrapper/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-nodejs-awssdk" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | // TODO(anuraaga): Add default when a public layer is published. 11 | } 12 | 13 | variable "sdk_layer_arn" { 14 | type = string 15 | description = "ARN for the Lambda layer containing the OpenTelemetry NodeJS Wrapper" 16 | // TODO(anuraaga): Add default when a public layer is published. 17 | } 18 | 19 | variable "tracing_mode" { 20 | type = string 21 | description = "Lambda function tracing mode" 22 | default = "PassThrough" 23 | } 24 | 25 | variable "architecture" { 26 | type = string 27 | description = "Lambda function architecture, valid values are arm64 or x86_64" 28 | default = "x86_64" 29 | } 30 | 31 | variable "runtime" { 32 | type = string 33 | description = "NodeJS runtime version used for sample Lambda Function" 34 | default = "nodejs18.x" 35 | } 36 | 37 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@opentelemetry-samples/lambda-awssdk", 3 | "version": "0.0.0", 4 | "private": true, 5 | "description": "Sample application for AWS Lambda using AWS SDK v2.", 6 | "main": "build/src/index.js", 7 | "types": "build/src/index.d.ts", 8 | "repository": "open-telemetry/opentelemetry-lambda", 9 | "scripts": { 10 | "clean": "rimraf build/*", 11 | "lint": "ESLINT_USE_FLAT_CONFIG=false eslint . --ext .ts", 12 | "lint:fix": "ESLINT_USE_FLAT_CONFIG=false eslint . --ext .ts --fix", 13 | "build": "npm run clean && npm run compile && npm run postcompile", 14 | "compile": "tsc -p .", 15 | "postcompile": "copyfiles 'package*.json' build/src/ && npm install --production --ignore-scripts --prefix build/src/ && cd build/src && bestzip ../function.zip *" 16 | }, 17 | "keywords": [ 18 | "opentelemetry", 19 | "awslambda", 20 | "nodejs", 21 | "tracing", 22 | "profiling", 23 | "instrumentation" 24 | ], 25 | "author": "OpenTelemetry Authors", 26 | "license": "Apache-2.0", 27 | "engines": { 28 | "node": ">=16.0.0" 29 | }, 30 | "files": [ 31 | "build/src/**/*.js", 32 | "build/src/**/*.d.ts", 33 | "doc", 34 | "LICENSE", 35 | "README.md" 36 | ], 37 | "devDependencies": { 38 | "@types/aws-lambda": "8.10.149", 39 | "@types/node": "22.15.29", 40 | "bestzip": "2.2.1", 41 | "copyfiles": "2.4.1", 42 | "rimraf": "6.0.1", 43 | "ts-node": "10.9.2", 44 | "typescript": "5.8.3" 45 | }, 46 | "dependencies": { 47 | "aws-sdk": "2.1692.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | APIGatewayProxyEvent, 3 | APIGatewayProxyResult, 4 | Context, 5 | } from 'aws-lambda'; 6 | 7 | import AWS from 'aws-sdk'; 8 | 9 | const s3 = new AWS.S3(); 10 | 11 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 12 | exports.handler = async (_event: APIGatewayProxyEvent, _context: Context) => { 13 | console.info('Serving lambda request.'); 14 | 15 | const result = await s3.listBuckets().promise(); 16 | 17 | const response: APIGatewayProxyResult = { 18 | statusCode: 200, 19 | body: `Hello lambda - found ${result.Buckets?.length || 0} buckets`, 20 | }; 21 | return response; 22 | }; 23 | -------------------------------------------------------------------------------- /nodejs/sample-apps/aws-sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "build" 6 | }, 7 | "include": [ 8 | "src/**/*.ts", 9 | "test/**/*.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /nodejs/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowUnreachableCode": false, 4 | "allowUnusedLabels": false, 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "module": "commonjs", 10 | "noEmitOnError": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "noImplicitReturns": true, 13 | "noUnusedLocals": true, 14 | "pretty": true, 15 | "sourceMap": true, 16 | "strict": true, 17 | "strictNullChecks": true, 18 | "target": "es2022", 19 | "incremental": true, 20 | "newLine": "LF" 21 | }, 22 | "exclude": [ 23 | "node_modules" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /nodejs/tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2022", 5 | "target": "es2022", 6 | "allowUnreachableCode": false, 7 | "allowUnusedLabels": false, 8 | "declaration": true, 9 | "declarationMap": true, 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noEmitOnError": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "noImplicitReturns": true, 15 | "noUnusedLocals": true, 16 | "pretty": true, 17 | "sourceMap": true, 18 | "strict": true, 19 | "strictNullChecks": true, 20 | "incremental": true, 21 | "newLine": "LF" 22 | }, 23 | "exclude": [ 24 | "node_modules" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Lambda Python 2 | 3 | Scripts and files used to build AWS Lambda Layers for running OpenTelemetry on AWS Lambda for Python. 4 | 5 | ### Sample App 6 | 7 | 1. Install 8 | * [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) 9 | * [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) 10 | * [Go](https://go.dev/doc/install) 11 | * [Docker](https://docs.docker.com/get-docker) 12 | 2. Run aws configure to [set aws credential(with administrator permissions)](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-mac.html#serverless-sam-cli-install-mac-iam-permissions) and default region. 13 | 3. Download a local copy of this repository from Github. 14 | 4. Navigate to the path `cd python/src` 15 | 5. If you just want to create a zip file with the OpenTelemetry Python AWS Lambda layer, then use the `-b true` option: `bash run.sh -n -b true` 16 | 6. If you want to create the layer and automatically publish it, use no options: `bash run.sh` 17 | -------------------------------------------------------------------------------- /python/sample-apps/aws-sdk/deploy/wrapper/main.tf: -------------------------------------------------------------------------------- 1 | module "hello-lambda-function" { 2 | source = "terraform-aws-modules/lambda/aws" 3 | version = ">= 2.24.0" 4 | 5 | architectures = compact([var.architecture]) 6 | function_name = var.name 7 | handler = "lambda_function.lambda_handler" 8 | runtime = var.runtime 9 | 10 | create_package = false 11 | local_existing_package = "${path.module}/../../../build/function.zip" 12 | 13 | memory_size = 384 14 | timeout = 20 15 | 16 | layers = compact([ 17 | var.collector_layer_arn, 18 | var.sdk_layer_arn 19 | ]) 20 | 21 | environment_variables = { 22 | AWS_LAMBDA_EXEC_WRAPPER = "/opt/otel-instrument" 23 | } 24 | 25 | tracing_mode = var.tracing_mode 26 | 27 | attach_policy_statements = true 28 | policy_statements = { 29 | s3 = { 30 | effect = "Allow" 31 | actions = [ 32 | "s3:ListAllMyBuckets" 33 | ] 34 | resources = [ 35 | "*" 36 | ] 37 | } 38 | } 39 | } 40 | 41 | module "api-gateway" { 42 | source = "../../../../../utils/terraform/api-gateway-proxy" 43 | 44 | name = var.name 45 | function_name = module.hello-lambda-function.lambda_function_name 46 | function_invoke_arn = module.hello-lambda-function.lambda_function_invoke_arn 47 | enable_xray_tracing = var.tracing_mode == "Active" 48 | } 49 | -------------------------------------------------------------------------------- /python/sample-apps/aws-sdk/deploy/wrapper/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api-gateway-url" { 2 | value = module.api-gateway.api_gateway_url 3 | } 4 | 5 | output "function_role_name" { 6 | value = module.hello-lambda-function.lambda_role_name 7 | } 8 | -------------------------------------------------------------------------------- /python/sample-apps/aws-sdk/deploy/wrapper/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of created function and API Gateway" 4 | default = "hello-python" 5 | } 6 | 7 | variable "collector_layer_arn" { 8 | type = string 9 | description = "ARN for the Lambda layer containing the OpenTelemetry collector extension" 10 | // TODO(anuraaga): Add default when a public layer is published. 11 | } 12 | 13 | variable "sdk_layer_arn" { 14 | type = string 15 | description = "ARN for the Lambda layer containing the OpenTelemetry Python Wrapper" 16 | // TODO(anuraaga): Add default when a public layer is published. 17 | } 18 | 19 | variable "tracing_mode" { 20 | type = string 21 | description = "Lambda function tracing mode" 22 | default = "PassThrough" 23 | } 24 | 25 | variable "architecture" { 26 | type = string 27 | description = "Lambda function architecture, valid values are arm64 or x86_64" 28 | default = "x86_64" 29 | } 30 | 31 | variable "runtime" { 32 | type = string 33 | description = "Python runtime version used for sample Lambda Function" 34 | default = "python3.9" 35 | } 36 | -------------------------------------------------------------------------------- /python/sample-apps/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p build/python 5 | python3 -m pip install -r function/requirements.txt -t build/python 6 | cp function/lambda_function.py build/python 7 | cd build/python 8 | zip -r ../function.zip ./* 9 | -------------------------------------------------------------------------------- /python/sample-apps/function/lambda_function.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import boto3 4 | import requests 5 | 6 | s3 = boto3.resource("s3") 7 | 8 | # lambda function 9 | def lambda_handler(event, context): 10 | 11 | requests.get("http://httpbin.org/") 12 | 13 | for bucket in s3.buckets.all(): 14 | print(bucket.name) 15 | 16 | return {"statusCode": 200, "body": json.dumps(os.environ.get("_X_AMZN_TRACE_ID"))} 17 | -------------------------------------------------------------------------------- /python/sample-apps/function/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | boto3 -------------------------------------------------------------------------------- /python/sample-apps/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euf -o pipefail 3 | 4 | cp -r ../src/otel . 5 | cp ../src/run.sh layer.sh 6 | ./layer.sh "$@" 7 | rm -rf .aws-sam 8 | rm -rf otel 9 | rm -r layer.sh 10 | -------------------------------------------------------------------------------- /python/sample-apps/template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: 'AWS::Serverless-2016-10-31' 3 | Description: OpenTelemetry Python Lambda layer for Python 4 | Resources: 5 | api: 6 | Type: AWS::Serverless::Api 7 | Properties: 8 | StageName: api 9 | TracingEnabled: true 10 | OpenApiVersion: 3.0.2 11 | function: 12 | Type: AWS::Serverless::Function 13 | Properties: 14 | Handler: lambda_function.lambda_handler 15 | Runtime: python3.9 16 | CodeUri: ./function 17 | Description: Build OTel Python Lambda Sample from scratch 18 | MemorySize: 512 19 | Timeout: 15 20 | Policies: 21 | - AWSLambdaBasicExecutionRole 22 | - AWSLambda_ReadOnlyAccess 23 | - AWSXrayWriteOnlyAccess 24 | - AmazonS3FullAccess 25 | Environment: 26 | Variables: 27 | AWS_LAMBDA_EXEC_WRAPPER: /opt/python/otel-instrument 28 | Tracing: Active 29 | Layers: 30 | - !Ref OTelLayer 31 | Events: 32 | getEndpoint: 33 | Type: Api 34 | Properties: 35 | RestApiId: !Ref api 36 | Path: / 37 | Method: GET 38 | OTelLayer: 39 | Type: AWS::Serverless::LayerVersion 40 | Properties: 41 | LayerName: opentelemetry-python 42 | Description: Opentelemetry Python layer 43 | ContentUri: ./otel 44 | CompatibleRuntimes: 45 | - python3.8 46 | - python3.9 47 | - python3.10 48 | - python3.11 49 | - python3.12 50 | - python3.13 51 | Metadata: 52 | BuildMethod: makefile 53 | -------------------------------------------------------------------------------- /python/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p build 5 | docker build --progress plain -t aws-otel-lambda-python-layer otel 6 | docker run --rm -v "$(pwd)/build:/out" aws-otel-lambda-python-layer 7 | -------------------------------------------------------------------------------- /python/src/otel/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG runtime=python3.13 2 | 3 | FROM public.ecr.aws/sam/build-${runtime} 4 | 5 | ADD . /workspace 6 | 7 | WORKDIR /workspace 8 | 9 | RUN mkdir -p /build && \ 10 | python3 -m pip install -r otel_sdk/requirements.txt -t /build/python && \ 11 | python3 -m pip install -r otel_sdk/nodeps-requirements.txt -t /build/tmp --no-deps && \ 12 | # We need to use a `/build/tmp/` folder otherwise the instrumentation packages 13 | # do not get fully downloaded to the `opentelemetry/instrumentation/` path. 14 | cp -r /build/tmp/* /build/python/ && \ 15 | rm -rf /build/tmp && \ 16 | mv otel_sdk/otel_wrapper.py /build/python && \ 17 | mv otel_sdk/otel-instrument /build && \ 18 | chmod 755 /build/otel-instrument && \ 19 | rm -rf /build/python/boto* && \ 20 | rm -rf /build/python/urllib3* && \ 21 | cd /build && \ 22 | zip -r opentelemetry-python-layer.zip otel-instrument python 23 | 24 | CMD cp /build/opentelemetry-python-layer.zip /out/opentelemetry-python-layer.zip 25 | -------------------------------------------------------------------------------- /python/src/otel/Makefile: -------------------------------------------------------------------------------- 1 | export SDK=$(shell pwd)/otel_sdk 2 | 3 | build-OTelLayer: 4 | mkdir -p $(ARTIFACTS_DIR)/python 5 | python3 -m pip install -r $(SDK)/requirements.txt -t $(ARTIFACTS_DIR)/python 6 | python3 -m pip install -r $(SDK)/nodeps-requirements.txt -t $(ARTIFACTS_DIR)/tmp --no-deps 7 | python3 -m pip freeze --path $(ARTIFACTS_DIR)/python 8 | cp -r $(ARTIFACTS_DIR)/tmp/* $(ARTIFACTS_DIR)/python/ 9 | rm -rf $(ARTIFACTS_DIR)/tmp 10 | cp -r $(SDK)/* $(ARTIFACTS_DIR)/python 11 | chmod 755 $(ARTIFACTS_DIR)/python/otel-instrument 12 | rm -rf $(ARTIFACTS_DIR)/python/boto* 13 | rm -rf $(ARTIFACTS_DIR)/python/urllib3* 14 | -------------------------------------------------------------------------------- /python/src/otel/otel_sdk/nodeps-requirements.txt: -------------------------------------------------------------------------------- 1 | # TODO: move these dependencies to requirements.txt when they stopped relying on a pinned version of 2 | # opentelemetry-propagator-aws-xray 3 | opentelemetry-instrumentation-aws-lambda==0.54b1 4 | opentelemetry-instrumentation-botocore==0.54b1 5 | -------------------------------------------------------------------------------- /python/src/otel/otel_sdk/otel_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright The OpenTelemetry Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | `otel_wrapper.py` 17 | 18 | This file serves as a wrapper over the user's Lambda function. 19 | 20 | Usage 21 | ----- 22 | Patch the reserved `_HANDLER` Lambda environment variable to point to this 23 | file's `otel_wrapper.lambda_handler` property. Do this having saved the original 24 | `_HANDLER` in the `ORIG_HANDLER` environment variable. Doing this makes it so 25 | that **on import of this file, the handler is instrumented**. 26 | 27 | Instrumenting any earlier will cause the instrumentation to be lost because the 28 | AWS Service uses `imp.load_module` to import the handler which RELOADS the 29 | module. This is why AwsLambdaInstrumentor cannot be instrumented with the 30 | `opentelemetry-instrument` script. 31 | 32 | See more: 33 | https://docs.python.org/3/library/imp.html#imp.load_module 34 | 35 | """ 36 | 37 | import os 38 | from importlib import import_module 39 | 40 | from opentelemetry.instrumentation.aws_lambda import AwsLambdaInstrumentor 41 | 42 | 43 | def modify_module_name(module_name): 44 | """Returns a valid modified module to get imported""" 45 | return ".".join(module_name.split("/")) 46 | 47 | 48 | class HandlerError(Exception): 49 | pass 50 | 51 | 52 | AwsLambdaInstrumentor().instrument() 53 | 54 | path = os.environ.get("ORIG_HANDLER") 55 | 56 | if path is None: 57 | raise HandlerError("ORIG_HANDLER is not defined.") 58 | 59 | try: 60 | (mod_name, handler_name) = path.rsplit(".", 1) 61 | except ValueError as e: 62 | raise HandlerError("Bad path '{}' for ORIG_HANDLER: {}".format(path, str(e))) 63 | 64 | modified_mod_name = modify_module_name(mod_name) 65 | handler_module = import_module(modified_mod_name) 66 | lambda_handler = getattr(handler_module, handler_name) 67 | -------------------------------------------------------------------------------- /python/src/otel/otel_sdk/requirements.txt: -------------------------------------------------------------------------------- 1 | opentelemetry-sdk==1.33.1 2 | opentelemetry-exporter-otlp-proto-http==1.33.1 3 | opentelemetry-distro==0.54b1 4 | opentelemetry-instrumentation==0.54b1 5 | opentelemetry-semantic-conventions==0.54b1 6 | opentelemetry-propagator-aws-xray==1.0.2 7 | 8 | # Instrumentation dependencies 9 | opentelemetry-instrumentation-aiohttp-client==0.54b1 10 | opentelemetry-util-http==0.54b1 11 | opentelemetry-instrumentation-asgi==0.54b1 12 | opentelemetry-instrumentation-asyncpg==0.54b1 13 | opentelemetry-instrumentation-boto==0.54b1 14 | opentelemetry-instrumentation-boto3sqs==0.54b1 15 | opentelemetry-instrumentation-celery==0.54b1 16 | opentelemetry-instrumentation-dbapi==0.54b1 17 | opentelemetry-instrumentation-django==0.54b1 18 | opentelemetry-instrumentation-elasticsearch==0.54b1 19 | opentelemetry-instrumentation-fastapi==0.54b1 20 | opentelemetry-instrumentation-falcon==0.54b1 21 | opentelemetry-instrumentation-flask==0.54b1 22 | opentelemetry-instrumentation-grpc==0.54b1 23 | opentelemetry-instrumentation-jinja2==0.54b1 24 | opentelemetry-instrumentation-mysql==0.54b1 25 | opentelemetry-instrumentation-psycopg2==0.54b1 26 | opentelemetry-instrumentation-pymemcache==0.54b1 27 | opentelemetry-instrumentation-pymongo==0.54b1 28 | opentelemetry-instrumentation-pymysql==0.54b1 29 | opentelemetry-instrumentation-pyramid==0.54b1 30 | opentelemetry-instrumentation-redis==0.54b1 31 | opentelemetry-instrumentation-requests==0.54b1 32 | opentelemetry-instrumentation-sqlalchemy==0.54b1 33 | opentelemetry-instrumentation-sqlite3==0.54b1 34 | opentelemetry-instrumentation-starlette==0.54b1 35 | opentelemetry-instrumentation-tornado==0.54b1 36 | opentelemetry-instrumentation-wsgi==0.54b1 37 | -------------------------------------------------------------------------------- /python/src/otel/tests/mocks/lambda_function.py: -------------------------------------------------------------------------------- 1 | # Copyright The OpenTelemetry Authors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | def handler(event, context): 17 | return "200 ok" 18 | -------------------------------------------------------------------------------- /python/src/otel/tests/nodeps-requirements.txt: -------------------------------------------------------------------------------- 1 | opentelemetry-instrumentation-aws-lambda==0.54b1 2 | -------------------------------------------------------------------------------- /python/src/otel/tests/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies used in tests only 2 | opentelemetry-test-utils==0.54b1 3 | opentelemetry-instrumentation == 0.54b1 4 | opentelemetry-semantic-conventions == 0.54b1 5 | opentelemetry-propagator-aws-xray == 1.0.2 6 | -------------------------------------------------------------------------------- /python/src/run.sh: -------------------------------------------------------------------------------- 1 | ../../utils/sam/run.sh -------------------------------------------------------------------------------- /python/src/template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: 'AWS::Serverless-2016-10-31' 3 | Description: OpenTelemetry Python Lambda layer for Python 4 | Parameters: 5 | LayerName: 6 | Type: String 7 | Description: Lambda layer name to be published 8 | Default: opentelemetry-python 9 | Resources: 10 | OTelLayer: 11 | Type: AWS::Serverless::LayerVersion 12 | Properties: 13 | LayerName: !Ref LayerName 14 | Description: Opentelemetry Python layer 15 | ContentUri: ./otel 16 | CompatibleRuntimes: 17 | - python3.8 18 | - python3.9 19 | - python3.10 20 | - python3.11 21 | - python3.12 22 | - python3.13 23 | Metadata: 24 | BuildMethod: makefile 25 | -------------------------------------------------------------------------------- /python/src/tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = 3 | ; opentelemetry-instrumentation-aws-lambda 4 | py3{8,9,10,11,12}-test-instrumentation-aws-lambda 5 | 6 | minversion = 3.8 7 | 8 | skip_missing_interpreters = True 9 | 10 | skipsdist = True 11 | 12 | [testenv] 13 | passenv = TOXENV 14 | 15 | setenv = 16 | OTEL_PYTHON_TRACER_PROVIDER=sdk_tracer_provider 17 | 18 | changedir = 19 | test-instrumentation-aws-lambda: {toxinidir}/otel/tests 20 | 21 | commands_pre = 22 | pip install -r requirements.txt 23 | pip install --no-deps -r nodeps-requirements.txt 24 | 25 | deps = 26 | pytest 27 | 28 | commands = 29 | pytest {posargs} 30 | -------------------------------------------------------------------------------- /ruby/sample-apps/function/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # need this empty gemfile for success build 4 | -------------------------------------------------------------------------------- /ruby/sample-apps/function/lambda_function.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | def lambda_handler(event:, context:) 4 | if defined?(::OpenTelemetry::SDK) 5 | { statusCode: 200, body: "Hello #{::OpenTelemetry::SDK::VERSION}" } 6 | else 7 | { statusCode: 200, body: "Missing OpenTelemetry" } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ruby/sample-apps/template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: 'AWS::Serverless-2016-10-31' 3 | Description: OpenTelemetry Ruby Lambda layer for Ruby 4 | Parameters: 5 | LayerName: 6 | Type: String 7 | Description: Lambda layer name to be published 8 | Default: opentelemetry-ruby 9 | Resources: 10 | OTelLayer: 11 | Type: AWS::Serverless::LayerVersion 12 | Properties: 13 | LayerName: !Ref LayerName 14 | Description: Opentelemetry Ruby layer 15 | ContentUri: ./../src/otel/layer 16 | CompatibleRuntimes: 17 | - ruby3.2 18 | Metadata: 19 | BuildMethod: makefile 20 | api: 21 | Type: AWS::Serverless::Api 22 | Properties: 23 | StageName: api 24 | OpenApiVersion: 3.0.2 25 | function: 26 | Type: AWS::Serverless::Function 27 | Properties: 28 | CodeUri: ./function 29 | Handler: lambda_function.lambda_handler 30 | Runtime: ruby3.2 31 | Description: Build OTel Ruby Lambda layer and sample app from scratch 32 | Policies: 33 | - AmazonS3ReadOnlyAccess 34 | Layers: 35 | - !Ref OTelLayer 36 | Events: 37 | getEndpoint: 38 | Type: Api 39 | Properties: 40 | RestApiId: !Ref api 41 | Path: / 42 | Method: GET 43 | Timeout: 60 44 | Environment: 45 | Variables: 46 | AWS_LAMBDA_EXEC_WRAPPER: /opt/otel-handler 47 | -------------------------------------------------------------------------------- /ruby/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p build 5 | 6 | docker build --progress plain -t aws-otel-lambda-ruby-layer otel 7 | docker run --rm -v "$(pwd)/build:/out" aws-otel-lambda-ruby-layer 8 | -------------------------------------------------------------------------------- /ruby/src/otel/layer/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'opentelemetry-sdk', '~> 1.8.0' 4 | gem 'opentelemetry-exporter-otlp', '~> 0.30.0' 5 | gem 'opentelemetry-instrumentation-all', '~> 0.76.0' 6 | -------------------------------------------------------------------------------- /ruby/src/otel/layer/Makefile: -------------------------------------------------------------------------------- 1 | 2 | build-OTelLayer: 3 | mkdir -p $(ARTIFACTS_DIR)/ruby/gems/3.2.0 4 | bundle config set --global silence_root_warning 1 5 | bundle config set --local path 'ruby' 6 | bundle install 7 | cp -r ruby/ruby/3.2.0/* $(ARTIFACTS_DIR)/ruby/gems/3.2.0 8 | cp otel-handler $(ARTIFACTS_DIR)/otel-handler 9 | cp wrapper.rb $(ARTIFACTS_DIR)/wrapper.rb 10 | rm -rf $(ARTIFACTS_DIR)/ruby/gems/3.2.0/cache 11 | -------------------------------------------------------------------------------- /ruby/src/otel/layer/otel-handler: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export ORIG_HANDLER="$_HANDLER"; 4 | export _HANDLER="/opt/wrapper.otel_wrapper"; 5 | 6 | if [ -z "${OTEL_SERVICE_NAME}" ]; then 7 | export OTEL_SERVICE_NAME="$AWS_LAMBDA_FUNCTION_NAME"; 8 | fi 9 | 10 | # disable HTTP NET by default - otherwise, lambda runtime gets instrumented yielding noise 11 | if [ -z "${OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED}" ]; then 12 | export OTEL_RUBY_INSTRUMENTATION_NET_HTTP_ENABLED=false; 13 | fi 14 | 15 | export LAMBDA_RESOURCE_ATTRIBUTES="cloud.region=$AWS_REGION,cloud.provider=aws,faas.name=$AWS_LAMBDA_FUNCTION_NAME,faas.version=$AWS_LAMBDA_FUNCTION_VERSION,faas.instance=$AWS_LAMBDA_LOG_STREAM_NAME"; 16 | if [ -z "${OTEL_RESOURCE_ATTRIBUTES}" ]; then 17 | export OTEL_RESOURCE_ATTRIBUTES="$LAMBDA_RESOURCE_ATTRIBUTES"; 18 | else 19 | export OTEL_RESOURCE_ATTRIBUTES="$LAMBDA_RESOURCE_ATTRIBUTES,$OTEL_RESOURCE_ATTRIBUTES"; 20 | fi 21 | 22 | exec "$@" 23 | -------------------------------------------------------------------------------- /ruby/src/otel/layer/wrapper.rb: -------------------------------------------------------------------------------- 1 | require 'opentelemetry-sdk' 2 | require 'opentelemetry-exporter-otlp' 3 | require 'opentelemetry-instrumentation-all' 4 | 5 | # We need to load the function code's dependencies, and _before_ any dependencies might 6 | # be initialized outside of the function handler, bootstrap instrumentation. 7 | def preload_function_dependencies 8 | default_task_location = '/var/task' 9 | 10 | handler_file = ENV.values_at('ORIG_HANDLER', '_HANDLER').compact.first&.split('.')&.first 11 | 12 | unless handler_file && File.exist?("#{default_task_location}/#{handler_file}.rb") 13 | OpenTelemetry.logger.warn { 'Could not find the original handler file to preload libraries.' } 14 | return nil 15 | end 16 | 17 | libraries = File.read("#{default_task_location}/#{handler_file}.rb") 18 | .scan(/^\s*require\s+['"]([^'"]+)['"]/) 19 | .flatten 20 | 21 | libraries.each do |lib| 22 | require lib 23 | rescue StandardError => e 24 | OpenTelemetry.logger.warn { "Could not load library #{lib}: #{e.message}" } 25 | end 26 | handler_file 27 | end 28 | 29 | handler_file = preload_function_dependencies 30 | 31 | OpenTelemetry.logger.info { "Libraries in #{handler_file} have been preloaded." } if handler_file 32 | 33 | OpenTelemetry::SDK.configure do |c| 34 | c.use_all() 35 | end 36 | 37 | def otel_wrapper(event:, context:) 38 | otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new 39 | otel_wrapper.call_wrapped(event: event, context: context) 40 | end 41 | -------------------------------------------------------------------------------- /ruby/src/template.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: 'AWS::Serverless-2016-10-31' 3 | Description: OpenTelemetry Ruby Lambda layer for Ruby 4 | Parameters: 5 | LayerName: 6 | Type: String 7 | Description: Lambda layer name to be published 8 | Default: opentelemetry-ruby 9 | Resources: 10 | OTelLayer: 11 | Type: AWS::Serverless::LayerVersion 12 | Properties: 13 | LayerName: !Ref LayerName 14 | Description: Opentelemetry Ruby layer 15 | ContentUri: ./otel/layer 16 | CompatibleRuntimes: 17 | - ruby3.2 18 | Metadata: 19 | BuildMethod: makefile 20 | -------------------------------------------------------------------------------- /ruby/src/zip_ruby_layer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | set -u 5 | 6 | echo_usage() { 7 | echo "usage: Build Lambda layer/application by SAM" 8 | echo " -n " 9 | } 10 | 11 | main() { 12 | echo "running..." 13 | layerName="opentelemetry-ruby-layer" 14 | 15 | while getopts "n:h" opt; do 16 | case "${opt}" in 17 | h) 18 | echo_usage 19 | exit 0 20 | ;; 21 | n) 22 | layerName="${OPTARG}" 23 | ;; 24 | \?) 25 | exit 1 26 | ;; 27 | :) 28 | echo "Option -${OPTARG} requires an argument" >&2 29 | exit 1 30 | ;; 31 | esac 32 | done 33 | 34 | (cd .aws-sam/build/OTelLayer/ && zip -qr ../"$layerName".zip .) 35 | mv .aws-sam/build/"$layerName".zip . 36 | echo "Finished" 37 | } 38 | 39 | main "$@" 40 | -------------------------------------------------------------------------------- /utils/aws-cloudformation/aws-cf-stack-for-layer-publish.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | GitHubOrgName: 3 | Description: Name of the GitHub organization/user 4 | Type: String 5 | RepositoryName: 6 | Description: Name of the GitHub repository 7 | Type: String 8 | Default: "opentelemetry-lambda" 9 | 10 | Resources: 11 | Role: 12 | Type: AWS::IAM::Role 13 | Properties: 14 | RoleName: "github-otel-lambda-layer-publish-role" 15 | AssumeRolePolicyDocument: 16 | Statement: 17 | - Effect: Allow 18 | Action: sts:AssumeRoleWithWebIdentity 19 | Principal: 20 | Federated: !Ref GithubOIDC 21 | Condition: 22 | StringEquals: 23 | token.actions.githubusercontent.com:aud: "sts.amazonaws.com" 24 | StringLike: 25 | token.actions.githubusercontent.com:sub: !Sub "repo:${GitHubOrgName}/${RepositoryName}:*" 26 | Policies: 27 | - PolicyName: "github-otel-lambda-layer-publish-policy" 28 | PolicyDocument: 29 | Version: "2012-10-17" 30 | Statement: 31 | - Effect: Allow 32 | Action: 33 | - "lambda:GetLayer*" 34 | - "lambda:ListLayer*" 35 | - "lambda:AddLayer*" 36 | - "lambda:PublishLayer*" 37 | Resource: 38 | - !Sub "arn:aws:lambda:*:${AWS::AccountId}:layer:opentelemetry-*" 39 | - !Sub "arn:aws:lambda:*:${AWS::AccountId}:layer:opentelemetry-*:*" 40 | 41 | GithubOIDC: 42 | Type: AWS::IAM::OIDCProvider 43 | Properties: 44 | Url: "https://token.actions.githubusercontent.com" 45 | ClientIdList: 46 | - "sts.amazonaws.com" 47 | ThumbprintList: 48 | - "ffffffffffffffffffffffffffffffffffffffff" 49 | 50 | Outputs: 51 | RoleARN: 52 | Description: "ARN of the AWS IAM role to be assumed by Github for the OpenTelemetry Layer publishing" 53 | Value: !GetAtt Role.Arn 54 | -------------------------------------------------------------------------------- /utils/sam/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euf -o pipefail 4 | 5 | echo_usage() { 6 | echo "usage: Deploy Lambda layer/application by SAM" 7 | echo " -r " 8 | echo " -t " 9 | echo " -b " 10 | echo " -d " 11 | echo " -n " 12 | echo " -l " 13 | echo " -s " 14 | } 15 | 16 | is_sample() { 17 | if [[ $(pwd) == *"sample"* ]]; then 18 | echo 1 19 | else 20 | echo 0 21 | fi 22 | } 23 | 24 | main() { 25 | echo "running..." 26 | saved_args="$*" 27 | template='template.yml' 28 | build=false 29 | deploy=false 30 | layer=false 31 | 32 | stack=${OTEL_LAMBDA_STACK-"otel-stack"} 33 | layerName=${OTEL_LAMBDA_LAYER-"otel-layer"} 34 | 35 | while getopts "hbdlr:t:s:n:" opt; do 36 | case "${opt}" in 37 | h) 38 | echo_usage 39 | exit 0 40 | ;; 41 | b) 42 | build=true 43 | ;; 44 | d) 45 | deploy=true 46 | ;; 47 | n) 48 | layerName="${OPTARG}" 49 | ;; 50 | l) 51 | layer=true 52 | ;; 53 | r) 54 | region="${OPTARG}" 55 | ;; 56 | t) 57 | template="${OPTARG}" 58 | ;; 59 | s) 60 | stack="${OPTARG}" 61 | ;; 62 | \?) 63 | echo "Invalid option: -${OPTARG}" >&2 64 | exit 1 65 | ;; 66 | :) 67 | echo "Option -${OPTARG} requires an argument" >&2 68 | exit 1 69 | ;; 70 | esac 71 | done 72 | 73 | if [[ $deploy == true && $region == "" ]]; then 74 | region=${AWS_REGION-$(aws configure get region)} 75 | fi 76 | 77 | echo "Invoked with: ${saved_args}" 78 | 79 | if [[ $build == false && $deploy == false && $layer == false ]]; then 80 | build=true 81 | deploy=true 82 | layer=true 83 | fi 84 | 85 | if [[ $build == true ]]; then 86 | echo "sam building..." 87 | 88 | echo "run.sh: Starting sam build." 89 | sam build -u -t "$template" 90 | zip -qr "$layerName".zip .aws-sam/build 91 | fi 92 | 93 | if [[ $deploy == true ]]; then 94 | sam deploy --stack-name "$stack" --region "$region" --capabilities CAPABILITY_NAMED_IAM --resolve-s3 --parameter-overrides LayerName="$layerName" 95 | rm -rf otel/otel_collector 96 | rm -f "$layerName".zip 97 | fi 98 | 99 | if [[ $layer == true ]]; then 100 | echo -e "\nOTel Lambda layer ARN:" 101 | arn=$(aws lambda list-layer-versions --layer-name "$layerName" --region "$region" --query 'max_by(LayerVersions, &Version).LayerVersionArn') 102 | echo "${arn//\"/}" 103 | fi 104 | } 105 | 106 | rm -rf .aws-sam 107 | 108 | main "$@" 109 | -------------------------------------------------------------------------------- /utils/terraform/api-gateway-proxy/main.tf: -------------------------------------------------------------------------------- 1 | resource "aws_api_gateway_rest_api" "lambda_api_proxy" { 2 | name = var.name 3 | } 4 | 5 | resource "aws_api_gateway_resource" "lambda_api_proxy" { 6 | rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id 7 | parent_id = aws_api_gateway_rest_api.lambda_api_proxy.root_resource_id 8 | path_part = "{proxy+}" 9 | } 10 | 11 | resource "aws_api_gateway_method" "lambda_api_proxy" { 12 | rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id 13 | resource_id = aws_api_gateway_resource.lambda_api_proxy.id 14 | http_method = "ANY" 15 | authorization = "NONE" 16 | } 17 | 18 | resource "aws_api_gateway_integration" "lambda_api" { 19 | rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id 20 | resource_id = aws_api_gateway_method.lambda_api_proxy.resource_id 21 | http_method = aws_api_gateway_method.lambda_api_proxy.http_method 22 | 23 | integration_http_method = "POST" 24 | type = "AWS_PROXY" 25 | uri = var.function_invoke_arn 26 | } 27 | 28 | resource "aws_api_gateway_method" "lambda_api_proxy_root_nodejs" { 29 | rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id 30 | resource_id = aws_api_gateway_rest_api.lambda_api_proxy.root_resource_id 31 | http_method = "ANY" 32 | authorization = "NONE" 33 | } 34 | 35 | resource "aws_api_gateway_integration" "lambda_api_root_nodejs" { 36 | rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id 37 | resource_id = aws_api_gateway_method.lambda_api_proxy_root_nodejs.resource_id 38 | http_method = aws_api_gateway_method.lambda_api_proxy_root_nodejs.http_method 39 | 40 | integration_http_method = "POST" 41 | type = "AWS_PROXY" 42 | uri = var.function_invoke_arn 43 | } 44 | 45 | resource "aws_api_gateway_deployment" "lambda_api_proxy" { 46 | depends_on = [ 47 | aws_api_gateway_integration.lambda_api, 48 | aws_api_gateway_integration.lambda_api_root_nodejs, 49 | ] 50 | 51 | rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id 52 | } 53 | 54 | resource "aws_api_gateway_stage" "test" { 55 | stage_name = "default" 56 | rest_api_id = aws_api_gateway_rest_api.lambda_api_proxy.id 57 | deployment_id = aws_api_gateway_deployment.lambda_api_proxy.id 58 | xray_tracing_enabled = var.enable_xray_tracing 59 | } 60 | 61 | resource "aws_lambda_permission" "lambda_api_allow_gateway_nodejs" { 62 | action = "lambda:InvokeFunction" 63 | function_name = var.function_name 64 | qualifier = var.function_qualifier 65 | principal = "apigateway.amazonaws.com" 66 | source_arn = "${aws_api_gateway_rest_api.lambda_api_proxy.execution_arn}/*/*" 67 | } 68 | -------------------------------------------------------------------------------- /utils/terraform/api-gateway-proxy/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api_gateway_url" { 2 | value = aws_api_gateway_stage.test.invoke_url 3 | } 4 | -------------------------------------------------------------------------------- /utils/terraform/api-gateway-proxy/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | description = "Name of API gateway to create" 4 | } 5 | 6 | variable "function_name" { 7 | type = string 8 | description = "Name of function to proxy to" 9 | } 10 | 11 | variable "function_qualifier" { 12 | type = string 13 | default = null 14 | description = "Qualifier of function to proxy to" 15 | } 16 | 17 | variable "function_invoke_arn" { 18 | type = string 19 | description = "Invoke ARN of function to proxy to" 20 | } 21 | 22 | variable "enable_xray_tracing" { 23 | type = bool 24 | description = "Whether to enable xray tracing of the API gateway" 25 | default = false 26 | } 27 | --------------------------------------------------------------------------------