├── .circleci └── config.yml ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ ├── question-discussion.md │ └── security-vulnerability-report.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── release.yml └── workflows │ ├── add-to-project-v2.yml │ ├── apply-labels.yml │ ├── stale.yml │ └── validate-pr-title.yml ├── .gitignore ├── CHANGELOG.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS ├── LICENSE ├── LICENSES ├── github.com │ ├── aws │ │ └── aws-sdk-go │ │ │ ├── LICENSE.txt │ │ │ ├── NOTICE.txt │ │ │ └── internal │ │ │ └── sync │ │ │ └── singleflight │ │ │ └── LICENSE │ ├── facebookgo │ │ ├── clock │ │ │ └── LICENSE │ │ ├── limitgroup │ │ │ └── license │ │ └── muster │ │ │ └── license │ ├── honeycombio │ │ ├── honeycomb-lambda-extension │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ └── libhoney-go │ │ │ ├── LICENSE │ │ │ └── NOTICE │ ├── jmespath │ │ └── go-jmespath │ │ │ └── LICENSE │ ├── klauspost │ │ └── compress │ │ │ ├── LICENSE │ │ │ ├── internal │ │ │ └── snapref │ │ │ │ └── LICENSE │ │ │ └── zstd │ │ │ └── internal │ │ │ └── xxhash │ │ │ └── LICENSE.txt │ ├── sirupsen │ │ └── logrus │ │ │ └── LICENSE │ └── vmihailenco │ │ ├── msgpack │ │ └── v5 │ │ │ └── LICENSE │ │ └── tagparser │ │ └── v2 │ │ └── LICENSE ├── golang.org │ └── x │ │ └── sys │ │ └── unix │ │ └── LICENSE └── gopkg.in │ └── alexcesaro │ └── statsd.v2 │ └── LICENSE ├── Makefile ├── NOTICE ├── OSSMETADATA ├── README.md ├── RELEASING.md ├── SECURITY.md ├── SUPPORT.md ├── eventprocessor ├── eventprocessor.go └── eventprocessor_test.go ├── eventpublisher ├── eventpublisher.go └── eventpublisher_test.go ├── extension ├── client.go ├── client_test.go ├── config.go └── config_test.go ├── go.mod ├── go.sum ├── logsapi ├── client.go ├── client_test.go ├── server.go └── server_test.go ├── main.go └── publish.sh /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | go: circleci/go@1.7.1 5 | aws-cli: circleci/aws-cli@3.2.0 6 | 7 | # The Go we test and build against 8 | goversion: &goversion "1.24" 9 | 10 | jobs: 11 | test: 12 | executor: 13 | name: go/default 14 | tag: *goversion 15 | steps: 16 | - checkout 17 | - go/load-cache 18 | - go/mod-download 19 | - run: make test 20 | - store_test_results: 21 | path: ./unit-tests.xml 22 | - go/save-cache 23 | build_extension: 24 | executor: 25 | name: go/default 26 | tag: *goversion 27 | steps: 28 | - checkout 29 | - go/load-cache 30 | - go/mod-download 31 | - go/save-cache 32 | - run: 33 | name: "Build binaries and layer content ZIPs" 34 | environment: 35 | GOOS: linux 36 | command: make zips 37 | - run: 38 | name: "Copy binaries and ZIPs to persist for CI workspace" 39 | command: | 40 | mkdir -p ~/artifacts 41 | cp -R ./artifacts/* ~/artifacts/ 42 | - persist_to_workspace: 43 | root: ~/ 44 | paths: 45 | - artifacts 46 | - store_artifacts: 47 | path: ~/artifacts 48 | publish_aws: 49 | docker: 50 | - image: cimg/go:1.24 51 | steps: 52 | - attach_workspace: 53 | at: ~/ 54 | - checkout 55 | - aws-cli/setup: 56 | role-arn: ${AWS_ROLE_ARN} 57 | role-session-name: "honeycomb-lambda-extension" 58 | aws-region: AWS_REGION 59 | - run: 60 | name: "Publish extension to AWS" 61 | command: ./publish.sh 62 | publish_github: 63 | docker: 64 | - image: cibuilds/github:0.13.0 65 | steps: 66 | - attach_workspace: 67 | at: ~/ 68 | - run: 69 | name: "Artifacts being published" 70 | command: | 71 | echo "about to publish to tag ${CIRCLE_TAG}" 72 | ls -l ~/artifacts/* 73 | - run: 74 | name: "GHR Draft" 75 | command: ghr -draft -n ${CIRCLE_TAG} -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${CIRCLE_TAG} ~/artifacts/linux 76 | publish_s3: 77 | docker: 78 | - image: cimg/go:1.24 79 | steps: 80 | - attach_workspace: 81 | at: ~/ 82 | - aws-cli/setup: 83 | role-arn: ${AWS_ROLE_ARN} 84 | role-session-name: "honeycomb-lambda-extension" 85 | aws-region: AWS_REGION 86 | - run: 87 | name: "Artifacts being published" 88 | command: | 89 | echo "about to publish ${CIRCLE_TAG} to S3" 90 | ls -l ~/artifacts/* 91 | - run: 92 | name: "S3 Release" 93 | command: aws s3 cp ~/artifacts/linux s3://honeycomb-builds/honeycombio/honeycomb-lambda-extension/${CIRCLE_TAG}/ --recursive 94 | 95 | workflows: 96 | nightly: 97 | triggers: 98 | - schedule: 99 | cron: "0 0 * * *" 100 | filters: 101 | branches: 102 | only: 103 | - main 104 | jobs: 105 | - test 106 | 107 | build: 108 | jobs: 109 | - test: 110 | filters: 111 | tags: 112 | only: /.*/ 113 | - build_extension: 114 | context: Honeycomb Secrets for Public Repos 115 | filters: 116 | tags: 117 | only: /.*/ 118 | branches: 119 | ignore: 120 | - /pull\/.*/ 121 | - /dependabot\/.*/ 122 | - publish_s3: 123 | context: Honeycomb Secrets for Public Repos 124 | filters: 125 | tags: 126 | only: /^v.*/ 127 | branches: 128 | ignore: /.*/ 129 | requires: 130 | - test 131 | - build_extension 132 | - publish_aws: 133 | context: Honeycomb Secrets for Public Repos 134 | filters: 135 | tags: 136 | only: /^v.*/ 137 | branches: 138 | ignore: /.*/ 139 | requires: 140 | - test 141 | - build_extension 142 | - publish_github: 143 | context: Honeycomb Secrets for Public Repos 144 | filters: 145 | tags: 146 | only: /^v.*/ 147 | branches: 148 | ignore: /.*/ 149 | requires: 150 | - test 151 | - build_extension 152 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Code owners file. 2 | # This file controls who is tagged for review for any given pull request. 3 | 4 | # For anything not explicitly taken by someone else: 5 | * @honeycombio/pipeline-team 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Let us know if something is not working as expected 4 | title: '' 5 | labels: 'type: bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | 18 | **Versions** 19 | 20 | - Lambda runtime: 21 | - Lambda extension: 22 | 23 | 24 | **Steps to reproduce** 25 | 26 | 1. 27 | 28 | **Additional context** 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'type: enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | 16 | **Is your feature request related to a problem? Please describe.** 17 | 18 | 19 | **Describe the solution you'd like** 20 | 21 | 22 | **Describe alternatives you've considered** 23 | 24 | 25 | **Additional context** 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question-discussion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question/Discussion 3 | about: General question about how things work or a discussion 4 | title: '' 5 | labels: 'type: discussion' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/security-vulnerability-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Security vulnerability report 3 | about: Let us know if you discover a security vulnerability 4 | title: '' 5 | labels: 'type: security' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | **Versions** 16 | 17 | - Lambda runtime: 18 | - Lambda extension: 19 | 20 | **Description** 21 | 22 | (Please include any relevant CVE advisory links) 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 12 | 13 | ## Which problem is this PR solving? 14 | 15 | - 16 | 17 | ## Short description of the changes 18 | 19 | - 20 | 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | labels: 13 | - "type: dependencies" 14 | commit-message: 15 | prefix: "maint" 16 | include: "scope" 17 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | # .github/release.yml 2 | 3 | changelog: 4 | exclude: 5 | labels: 6 | - no-changelog 7 | categories: 8 | - title: 💥 Breaking Changes 💥 9 | labels: 10 | - "version: bump major" 11 | - breaking-change 12 | - title: 💡 Enhancements 13 | labels: 14 | - "type: enhancement" 15 | - title: 🐛 Fixes 16 | labels: 17 | - "type: bug" 18 | - title: 🛠 Maintenance 19 | labels: 20 | - "type: maintenance" 21 | - "type: dependencies" 22 | - "type: documentation" 23 | - title: 🤷 Other Changes 24 | labels: 25 | - "*" 26 | -------------------------------------------------------------------------------- /.github/workflows/add-to-project-v2.yml: -------------------------------------------------------------------------------- 1 | name: Add to project 2 | on: 3 | issues: 4 | types: [opened] 5 | pull_request_target: 6 | types: [opened] 7 | jobs: 8 | add-to-project: 9 | runs-on: ubuntu-latest 10 | name: Add issues and PRs to project 11 | steps: 12 | - uses: actions/add-to-project@main 13 | with: 14 | project-url: https://github.com/orgs/honeycombio/projects/27 15 | github-token: ${{ secrets.GHPROJECTS_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/apply-labels.yml: -------------------------------------------------------------------------------- 1 | name: Apply project labels 2 | on: [issues, pull_request_target, label] 3 | jobs: 4 | apply-labels: 5 | runs-on: ubuntu-latest 6 | name: Apply common project labels 7 | steps: 8 | - uses: honeycombio/oss-management-actions/labels@v1 9 | with: 10 | github-token: ${{ secrets.GITHUB_TOKEN }} 11 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '30 1 * * *' 5 | 6 | jobs: 7 | stale: 8 | name: 'Close stale issues and PRs' 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | 14 | steps: 15 | - uses: actions/stale@v4 16 | with: 17 | start-date: '2021-09-01T00:00:00Z' 18 | stale-issue-message: 'Marking this issue as stale because it has been open 14 days with no activity. Please add a comment if this is still an ongoing issue; otherwise this issue will be automatically closed in 7 days.' 19 | stale-pr-message: 'Marking this PR as stale because it has been open 30 days with no activity. Please add a comment if this PR is still relevant; otherwise this PR will be automatically closed in 7 days.' 20 | close-issue-message: 'Closing this issue due to inactivity. Please see our [Honeycomb OSS Lifecyle and Practices](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md).' 21 | close-pr-message: 'Closing this PR due to inactivity. Please see our [Honeycomb OSS Lifecyle and Practices](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md).' 22 | days-before-issue-stale: 14 23 | days-before-pr-stale: 30 24 | days-before-issue-close: 7 25 | days-before-pr-close: 7 26 | any-of-labels: 'status: info needed,status: revision needed' 27 | -------------------------------------------------------------------------------- /.github/workflows/validate-pr-title.yml: -------------------------------------------------------------------------------- 1 | name: "Validate PR Title" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | name: Validate PR title 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: amannn/action-semantic-pull-request@v5 16 | id: lint_pr_title 17 | name: "🤖 Check PR title follows conventional commit spec" 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | # Have to specify all types because `maint` and `rel` aren't defaults 22 | types: | 23 | maint 24 | rel 25 | fix 26 | feat 27 | chore 28 | ci 29 | docs 30 | style 31 | refactor 32 | perf 33 | test 34 | ignoreLabels: | 35 | "type: dependencies" 36 | # When the previous steps fails, the workflow would stop. By adding this 37 | # condition you can continue the execution with the populated error message. 38 | - if: always() && (steps.lint_pr_title.outputs.error_message != null) 39 | name: "📝 Add PR comment about using conventional commit spec" 40 | uses: marocchino/sticky-pull-request-comment@v2 41 | with: 42 | header: pr-title-lint-error 43 | message: | 44 | Thank you for contributing to the project! 🎉 45 | 46 | We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted. 47 | 48 | Make sure to prepend with `feat:`, `fix:`, or another option in the list below. 49 | 50 | Once you update the title, this workflow will re-run automatically and validate the updated title. 51 | 52 | Details: 53 | 54 | ``` 55 | ${{ steps.lint_pr_title.outputs.error_message }} 56 | ``` 57 | 58 | # Delete a previous comment when the issue has been resolved 59 | - if: ${{ steps.lint_pr_title.outputs.error_message == null }} 60 | name: "❌ Delete PR comment after title has been updated" 61 | uses: marocchino/sticky-pull-request-comment@v2 62 | with: 63 | header: pr-title-lint-error 64 | delete: true 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | artifacts/ 2 | unit-tests.xml 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Honeycomb Lambda Extension Changelog 2 | 3 | ## v11.5.0 - 2025-06-03 4 | 5 | ### 💡 Enhancements 6 | 7 | - feat: add option to use kms encrypted keys by @JamieDanielson in https://github.com/honeycombio/honeycomb-lambda-extension/pull/159 8 | 9 | ### 🛠 Maintenance 10 | 11 | - chore: LICENSES update for new/updated dependencies included in builds by @robbkidd in https://github.com/honeycombio/honeycomb-lambda-extension/pull/160 12 | 13 | ## v11.4.0 - 2025-05-02 14 | 15 | This release fixes a security vulnerability in Go 1.22. 16 | 17 | ### Fixes: 18 | 19 | - maint: Bump go to 1.24 and some dependencies (#156) | [@Kent Quirk](https://github.com/kentquirk) 20 | 21 | ## v11.3.0 - 2025-02-19 22 | 23 | This release fixes a security vulnerability from standard library in go 1.19. 24 | 25 | ### Fixes 26 | 27 | - fix: bump go version to 1.22 (#154) | [@Yingrong Zhao](https://github.com/VinozzZ) 28 | 29 | ### Maintenance 30 | 31 | - maint(deps): bump github.com/honeycombio/libhoney-go from 1.24.0 to 1.25.0 (#153) | @dependabot 32 | - maint(deps): bump github.com/stretchr/testify from 1.9.0 to 1.10.0 (#152) | @dependabot 33 | - maint(deps): bump github.com/honeycombio/libhoney-go from 1.23.1 to 1.24.0 (#151) | @dependabot 34 | 35 | ## v11.2.0 - 2024-11-05 36 | 37 | ### Fixes 38 | 39 | - fix: forward the sample rate from the message (#146) | @NLincoln 40 | 41 | ### Maintenance 42 | 43 | - docs: update vulnerability reporting process (#144) | @robbkidd 44 | - maint: add labels to release.yml for auto-generated grouping (#142) | @JamieDanielson 45 | - maint: update codeowners to pipeline-team (#137) | @JamieDanielson 46 | - maint: update codeowners to pipeline (#136) | @JamieDanielson 47 | - maint(deps): bump github.com/honeycombio/libhoney-go from 1.20.0 to 1.23.1 (#147) | @dependabot 48 | - maint(deps): remove reviewers from dependabot.yml (#148) | @codeboten 49 | 50 | ## v11.1.2 - 2023-10-13 51 | 52 | ### Maintenance 53 | 54 | - maint(deps): bump github.com/sirupsen/logrus from 1.9.0 to 1.9.3 (#133) | dependabot[bot] 55 | - maint(deps): bump github.com/honeycombio/libhoney-go from 1.18.0 to 1.20.0 (#134) | dependabot[bot] 56 | - maint(deps): bump github.com/stretchr/testify from 1.8.2 to 1.8.4 (#130) | dependabot[bot] 57 | - maint(deps): bump github.com/stretchr/testify from 1.8.1 to 1.8.2 (#126) | dependabot[bot] 58 | - maint: Add dependency licenses (#127) | Mike Goldsmith 59 | 60 | ## v11.1.1 - 2023-02-27 61 | 62 | ### Maintenance 63 | 64 | - maint: Update AWS regions we publish to (#123) | [@MikeGoldsmith](https://github.com/MikeGoldsmith) 65 | - maint: Update CODEOWNERS (#122) | [@vreynolds](https://github.com/vreynolds) 66 | - chore: update dependabot.yml (#120) | [@kentquirk](https://github.com/kentquirk) 67 | - maint: remove duplicate GOARCH in user-agent (#117)| [@robbkidd](https://github.com/robbkidd) 68 | - Bump github.com/stretchr/testify from 1.8.0 to 1.8.1 (#115) 69 | - Bump github.com/honeycombio/libhoney-go from 1.17.0 to 1.18.0 (#116) 70 | 71 | ## v11.1.0 - 2022-10-24 72 | 73 | ### Enhancements 74 | 75 | - feat: configurable HTTP transport connect timeout (#111) | @danvendia 76 | 77 | ### Maintenance 78 | 79 | - maint: refactor config and simplify main() (#112) | @robbkidd 80 | 81 | ## v11.0.0 - 2022-10-13 82 | 83 | ### 💥 Breaking Changes 💥 84 | 85 | The extension's layer name has changed to include the project's SemVer release version. 86 | As a result of this name change, each release of the layer will have a new LayerArn and the LayerVersionArn will consistently end in `1`. 87 | 88 | ``` 89 | # Layer Version ARN Pattern 90 | arn:aws:lambda::702835727665:layer:honeycomb-lambda-extension--:1 91 | 92 | # Layer Version ARN Example 93 | arn:aws:lambda:us-east-1:702835727665:layer:honeycomb-lambda-extension-arm64-v11-0-0:1 94 | ``` 95 | 96 | ### Maintenance 97 | 98 | - maint: release process updates for friendlier ARNs (#103) | [@robbkidd](https://github.com/robbkidd) 99 | - maint: add new project workflow (#105) | [@vreynolds](https://github.com/vreynolds) 100 | - maint: add config for gh release notes organization (#107) | [@JamieDanielson](https://github.com/JamieDanielson) 101 | 102 | ## [v10.3.0] Layer version 11 - 2022-10-07 103 | 104 | ### Added 105 | 106 | - feat: configurable event batch send timeout (#98) | [@robbkidd](https://github.com/robbkidd) 107 | - add missing default regions (#93) | [@JamieDanielson](https://github.com/JamieDanielson) 108 | 109 | ### Maintenance 110 | 111 | - Bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0 (#90) 112 | - Bump github.com/honeycombio/libhoney-go from 1.15.8 to 1.17.0 (#99) 113 | - maint: add go 1.19 to CI (#96) | [@vreynolds](https://github.com/vreynolds) 114 | 115 | ## [v10.3.0] Layer version 10 - 2022-07-25 116 | 117 | ### Added 118 | 119 | - Add support for more AWS regions (#88) | [@pkanal](https://github.com/pkanal) 120 | 121 | ### Maintenance 122 | 123 | - Fixes OpenSSL CVE | [@pkanal](https://github.com/pkanal) 124 | 125 | ## [v10.2.0] Layer version 9 - 2022-04-08 126 | 127 | ### Added 128 | 129 | - Add shutdown reason event for timeouts and failures (#75) | [@danvendia](https://github.com/danvendia) 130 | 131 | ### Maintenance 132 | 133 | - Add go 1.18 to CI (#77) | [@vreynolds](https://github.com/vreynolds) 134 | - Bump github.com/stretchr/testify from 1.7.0 to 1.7.1 (#78) 135 | - Bump github.com/honeycombio/libhoney-go from 1.15.6 to 1.15.8 (#74) 136 | 137 | ## [v10.1.0] Layer version 8 - 2022-01-07 138 | 139 | ### Added 140 | 141 | - feat: use msgpack encoding when sending telemetry (#72) | [@vreynolds](https://github.com/vreynolds) 142 | 143 | ### Maintenance 144 | 145 | - ci: Add re-triage workflow (#71) | [@vreynolds](https://github.com/vreynolds) 146 | - docs: update layer version (#70) | [@vreynolds](https://github.com/vreynolds) 147 | 148 | ## [v10.0.3] Layer version 7 - 2021-11-18 149 | 150 | ### Maintenance 151 | 152 | - Put GOARCH into user agent (#65) | [@dstrelau](https://github.com/dstrelau) 153 | 154 | ## [v10.0.2] Layer version 6 - 2021-11-03 155 | 156 | ### Maintenance 157 | 158 | - bump libhoney-go (#63) 159 | - empower apply-labels action to apply labels (#62) 160 | - Bump github.com/honeycombio/libhoney-go from 1.15.4 to 1.15.5 (#53) 161 | - leave note for future adventurers (#59) 162 | - ci: fix s3 sync job (#57) 163 | - docs: update to latest version in readme (#58) 164 | 165 | ## [v10.0.1] Layer version 5 - 2021-10-01 166 | 167 | ### Fixed 168 | 169 | Release 10.0.0 had an issue with the published layer. 170 | 171 | - fix: aws publish layer directory name must be extensions (#55) 172 | - fix: split publish based on region support (#52) 173 | 174 | ## 10.0.0 (2021-09-29) 175 | 176 | ### Added 177 | 178 | - Support ARM build (#46) 179 | 180 | ### Maintenance 181 | 182 | - Change maintenance badge to maintained (#44) 183 | - Add Stalebot (#45) 184 | - Add NOTICE (#42) 185 | - Add note about honeycomb_debug env var (#41) 186 | - Update CI config (#40) 187 | - Bump github.com/stretchr/testify from 1.6.1 to 1.7.0 (#28) 188 | - Bump github.com/sirupsen/logrus from 1.7.0 to 1.8.1 (#30) 189 | - Bump github.com/honeycombio/libhoney-go from 1.14.1 to 1.15.4 (#32) 190 | 191 | ## 9.0.0 (2021-08-25) 192 | ### Added 193 | - Debugging mode via environment variable #38 194 | 195 | ## 8.0.0 (2021-05-17) 196 | ### Fixed 197 | - adds some configurable logging for troubleshooting extension behavior (#20) 198 | - parse JSON emitted to STDOUT from Beelines/libhoney and send along as events (#21) 199 | 200 | ## 7.0.0 (2021-05-14) 201 | ### Fixed 202 | - Flush events queue on wake up. (#16) 203 | 204 | ## Version 4 (2020-12-09) 205 | 206 | - The Logs API returns 202 on subscribe. We were checking for 200. 207 | 208 | ## Version 3 (2020-11-20) 209 | 210 | - Remove unnecessary panic when unable to subscribe to logs API 211 | - Add version string to user agent header 212 | 213 | ## Version 2 (2020-11-12) 214 | 215 | - Added option to disable `platform` messages. 216 | - Adding files like `CODEOWNERS`, `CONTRIBUTORS`, etc. 217 | 218 | ## Version 1 (2020-11-09) 219 | 220 | - Pre-release for testing and demos. 221 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | 2 | # Code owners file. 3 | # This file controls who is tagged for review for any given pull request. 4 | 5 | # For anything not explicitly taken by someone else: 6 | * @honeycombio/telemetry-team 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project has adopted the Honeycomb User Community Code of Conduct to clarify expected behavior in our community. 4 | 5 | https://www.honeycomb.io/honeycomb-user-community-code-of-conduct/ -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | Please see our [general guide for OSS lifecycle and practices.](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md) 4 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | Paul Osman 2 | Mike Goldsmith 3 | Ben Hartshorne -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 Hound Technology Inc 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSES/github.com/aws/aws-sdk-go/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSES/github.com/aws/aws-sdk-go/NOTICE.txt: -------------------------------------------------------------------------------- 1 | AWS SDK for Go 2 | Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | Copyright 2014-2015 Stripe, Inc. 4 | -------------------------------------------------------------------------------- /LICENSES/github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/github.com/facebookgo/clock/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ben Johnson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSES/github.com/facebookgo/limitgroup/license: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For limitgroup software 4 | 5 | Copyright (c) 2015, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /LICENSES/github.com/facebookgo/muster/license: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For muster software 4 | 5 | Copyright (c) 2015, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /LICENSES/github.com/honeycombio/honeycomb-lambda-extension/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 Hound Technology Inc 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSES/github.com/honeycombio/honeycomb-lambda-extension/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-Present Honeycomb, Hound Technology, Inc. All Rights Reserved. 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 | -------------------------------------------------------------------------------- /LICENSES/github.com/honeycombio/libhoney-go/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSES/github.com/honeycombio/libhoney-go/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-Present Honeycomb, Hound Technology, Inc. All Rights Reserved. 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 | -------------------------------------------------------------------------------- /LICENSES/github.com/jmespath/go-jmespath/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 James Saryerwinnie 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 | -------------------------------------------------------------------------------- /LICENSES/github.com/klauspost/compress/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | Copyright (c) 2019 Klaus Post. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | ------------------ 31 | 32 | Files: gzhttp/* 33 | 34 | Apache License 35 | Version 2.0, January 2004 36 | http://www.apache.org/licenses/ 37 | 38 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 39 | 40 | 1. Definitions. 41 | 42 | "License" shall mean the terms and conditions for use, reproduction, 43 | and distribution as defined by Sections 1 through 9 of this document. 44 | 45 | "Licensor" shall mean the copyright owner or entity authorized by 46 | the copyright owner that is granting the License. 47 | 48 | "Legal Entity" shall mean the union of the acting entity and all 49 | other entities that control, are controlled by, or are under common 50 | control with that entity. For the purposes of this definition, 51 | "control" means (i) the power, direct or indirect, to cause the 52 | direction or management of such entity, whether by contract or 53 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 54 | outstanding shares, or (iii) beneficial ownership of such entity. 55 | 56 | "You" (or "Your") shall mean an individual or Legal Entity 57 | exercising permissions granted by this License. 58 | 59 | "Source" form shall mean the preferred form for making modifications, 60 | including but not limited to software source code, documentation 61 | source, and configuration files. 62 | 63 | "Object" form shall mean any form resulting from mechanical 64 | transformation or translation of a Source form, including but 65 | not limited to compiled object code, generated documentation, 66 | and conversions to other media types. 67 | 68 | "Work" shall mean the work of authorship, whether in Source or 69 | Object form, made available under the License, as indicated by a 70 | copyright notice that is included in or attached to the work 71 | (an example is provided in the Appendix below). 72 | 73 | "Derivative Works" shall mean any work, whether in Source or Object 74 | form, that is based on (or derived from) the Work and for which the 75 | editorial revisions, annotations, elaborations, or other modifications 76 | represent, as a whole, an original work of authorship. For the purposes 77 | of this License, Derivative Works shall not include works that remain 78 | separable from, or merely link (or bind by name) to the interfaces of, 79 | the Work and Derivative Works thereof. 80 | 81 | "Contribution" shall mean any work of authorship, including 82 | the original version of the Work and any modifications or additions 83 | to that Work or Derivative Works thereof, that is intentionally 84 | submitted to Licensor for inclusion in the Work by the copyright owner 85 | or by an individual or Legal Entity authorized to submit on behalf of 86 | the copyright owner. For the purposes of this definition, "submitted" 87 | means any form of electronic, verbal, or written communication sent 88 | to the Licensor or its representatives, including but not limited to 89 | communication on electronic mailing lists, source code control systems, 90 | and issue tracking systems that are managed by, or on behalf of, the 91 | Licensor for the purpose of discussing and improving the Work, but 92 | excluding communication that is conspicuously marked or otherwise 93 | designated in writing by the copyright owner as "Not a Contribution." 94 | 95 | "Contributor" shall mean Licensor and any individual or Legal Entity 96 | on behalf of whom a Contribution has been received by Licensor and 97 | subsequently incorporated within the Work. 98 | 99 | 2. Grant of Copyright License. Subject to the terms and conditions of 100 | this License, each Contributor hereby grants to You a perpetual, 101 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 102 | copyright license to reproduce, prepare Derivative Works of, 103 | publicly display, publicly perform, sublicense, and distribute the 104 | Work and such Derivative Works in Source or Object form. 105 | 106 | 3. Grant of Patent License. Subject to the terms and conditions of 107 | this License, each Contributor hereby grants to You a perpetual, 108 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 109 | (except as stated in this section) patent license to make, have made, 110 | use, offer to sell, sell, import, and otherwise transfer the Work, 111 | where such license applies only to those patent claims licensable 112 | by such Contributor that are necessarily infringed by their 113 | Contribution(s) alone or by combination of their Contribution(s) 114 | with the Work to which such Contribution(s) was submitted. If You 115 | institute patent litigation against any entity (including a 116 | cross-claim or counterclaim in a lawsuit) alleging that the Work 117 | or a Contribution incorporated within the Work constitutes direct 118 | or contributory patent infringement, then any patent licenses 119 | granted to You under this License for that Work shall terminate 120 | as of the date such litigation is filed. 121 | 122 | 4. Redistribution. You may reproduce and distribute copies of the 123 | Work or Derivative Works thereof in any medium, with or without 124 | modifications, and in Source or Object form, provided that You 125 | meet the following conditions: 126 | 127 | (a) You must give any other recipients of the Work or 128 | Derivative Works a copy of this License; and 129 | 130 | (b) You must cause any modified files to carry prominent notices 131 | stating that You changed the files; and 132 | 133 | (c) You must retain, in the Source form of any Derivative Works 134 | that You distribute, all copyright, patent, trademark, and 135 | attribution notices from the Source form of the Work, 136 | excluding those notices that do not pertain to any part of 137 | the Derivative Works; and 138 | 139 | (d) If the Work includes a "NOTICE" text file as part of its 140 | distribution, then any Derivative Works that You distribute must 141 | include a readable copy of the attribution notices contained 142 | within such NOTICE file, excluding those notices that do not 143 | pertain to any part of the Derivative Works, in at least one 144 | of the following places: within a NOTICE text file distributed 145 | as part of the Derivative Works; within the Source form or 146 | documentation, if provided along with the Derivative Works; or, 147 | within a display generated by the Derivative Works, if and 148 | wherever such third-party notices normally appear. The contents 149 | of the NOTICE file are for informational purposes only and 150 | do not modify the License. You may add Your own attribution 151 | notices within Derivative Works that You distribute, alongside 152 | or as an addendum to the NOTICE text from the Work, provided 153 | that such additional attribution notices cannot be construed 154 | as modifying the License. 155 | 156 | You may add Your own copyright statement to Your modifications and 157 | may provide additional or different license terms and conditions 158 | for use, reproduction, or distribution of Your modifications, or 159 | for any such Derivative Works as a whole, provided Your use, 160 | reproduction, and distribution of the Work otherwise complies with 161 | the conditions stated in this License. 162 | 163 | 5. Submission of Contributions. Unless You explicitly state otherwise, 164 | any Contribution intentionally submitted for inclusion in the Work 165 | by You to the Licensor shall be under the terms and conditions of 166 | this License, without any additional terms or conditions. 167 | Notwithstanding the above, nothing herein shall supersede or modify 168 | the terms of any separate license agreement you may have executed 169 | with Licensor regarding such Contributions. 170 | 171 | 6. Trademarks. This License does not grant permission to use the trade 172 | names, trademarks, service marks, or product names of the Licensor, 173 | except as required for reasonable and customary use in describing the 174 | origin of the Work and reproducing the content of the NOTICE file. 175 | 176 | 7. Disclaimer of Warranty. Unless required by applicable law or 177 | agreed to in writing, Licensor provides the Work (and each 178 | Contributor provides its Contributions) on an "AS IS" BASIS, 179 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 180 | implied, including, without limitation, any warranties or conditions 181 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 182 | PARTICULAR PURPOSE. You are solely responsible for determining the 183 | appropriateness of using or redistributing the Work and assume any 184 | risks associated with Your exercise of permissions under this License. 185 | 186 | 8. Limitation of Liability. In no event and under no legal theory, 187 | whether in tort (including negligence), contract, or otherwise, 188 | unless required by applicable law (such as deliberate and grossly 189 | negligent acts) or agreed to in writing, shall any Contributor be 190 | liable to You for damages, including any direct, indirect, special, 191 | incidental, or consequential damages of any character arising as a 192 | result of this License or out of the use or inability to use the 193 | Work (including but not limited to damages for loss of goodwill, 194 | work stoppage, computer failure or malfunction, or any and all 195 | other commercial damages or losses), even if such Contributor 196 | has been advised of the possibility of such damages. 197 | 198 | 9. Accepting Warranty or Additional Liability. While redistributing 199 | the Work or Derivative Works thereof, You may choose to offer, 200 | and charge a fee for, acceptance of support, warranty, indemnity, 201 | or other liability obligations and/or rights consistent with this 202 | License. However, in accepting such obligations, You may act only 203 | on Your own behalf and on Your sole responsibility, not on behalf 204 | of any other Contributor, and only if You agree to indemnify, 205 | defend, and hold each Contributor harmless for any liability 206 | incurred by, or claims asserted against, such Contributor by reason 207 | of your accepting any such warranty or additional liability. 208 | 209 | END OF TERMS AND CONDITIONS 210 | 211 | APPENDIX: How to apply the Apache License to your work. 212 | 213 | To apply the Apache License to your work, attach the following 214 | boilerplate notice, with the fields enclosed by brackets "[]" 215 | replaced with your own identifying information. (Don't include 216 | the brackets!) The text should be enclosed in the appropriate 217 | comment syntax for the file format. We also recommend that a 218 | file or class name and description of purpose be included on the 219 | same "printed page" as the copyright notice for easier 220 | identification within third-party archives. 221 | 222 | Copyright 2016-2017 The New York Times Company 223 | 224 | Licensed under the Apache License, Version 2.0 (the "License"); 225 | you may not use this file except in compliance with the License. 226 | You may obtain a copy of the License at 227 | 228 | http://www.apache.org/licenses/LICENSE-2.0 229 | 230 | Unless required by applicable law or agreed to in writing, software 231 | distributed under the License is distributed on an "AS IS" BASIS, 232 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 233 | See the License for the specific language governing permissions and 234 | limitations under the License. 235 | 236 | ------------------ 237 | 238 | Files: s2/cmd/internal/readahead/* 239 | 240 | The MIT License (MIT) 241 | 242 | Copyright (c) 2015 Klaus Post 243 | 244 | Permission is hereby granted, free of charge, to any person obtaining a copy 245 | of this software and associated documentation files (the "Software"), to deal 246 | in the Software without restriction, including without limitation the rights 247 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 248 | copies of the Software, and to permit persons to whom the Software is 249 | furnished to do so, subject to the following conditions: 250 | 251 | The above copyright notice and this permission notice shall be included in all 252 | copies or substantial portions of the Software. 253 | 254 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 255 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 256 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 257 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 258 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 259 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 260 | SOFTWARE. 261 | 262 | --------------------- 263 | Files: snappy/* 264 | Files: internal/snapref/* 265 | 266 | Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. 267 | 268 | Redistribution and use in source and binary forms, with or without 269 | modification, are permitted provided that the following conditions are 270 | met: 271 | 272 | * Redistributions of source code must retain the above copyright 273 | notice, this list of conditions and the following disclaimer. 274 | * Redistributions in binary form must reproduce the above 275 | copyright notice, this list of conditions and the following disclaimer 276 | in the documentation and/or other materials provided with the 277 | distribution. 278 | * Neither the name of Google Inc. nor the names of its 279 | contributors may be used to endorse or promote products derived from 280 | this software without specific prior written permission. 281 | 282 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 283 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 284 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 285 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 286 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 287 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 288 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 289 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 290 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 291 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 292 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 293 | 294 | ----------------- 295 | 296 | Files: s2/cmd/internal/filepathx/* 297 | 298 | Copyright 2016 The filepathx Authors 299 | 300 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 301 | 302 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 303 | 304 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 305 | -------------------------------------------------------------------------------- /LICENSES/github.com/klauspost/compress/internal/snapref/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Caleb Spare 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /LICENSES/github.com/sirupsen/logrus/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Simon Eskildsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSES/github.com/vmihailenco/msgpack/v5/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 The github.com/vmihailenco/msgpack Authors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /LICENSES/github.com/vmihailenco/tagparser/v2/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 The github.com/vmihailenco/tagparser Authors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /LICENSES/golang.org/x/sys/unix/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/gopkg.in/alexcesaro/statsd.v2/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Alexandre Cesaro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Which operating system to target for a Go build? 2 | # Defaults to linux because the extension runs in a linux compute environment. 3 | # Override in development if you wish to build and run on your dev host. 4 | # Example: GOOS=darwin make build 5 | GOOS ?= linux 6 | 7 | # CIRCLE_TAG is generally not set unless CircleCI is running a workflow 8 | # triggered by a git tag creation. 9 | # If set, the value will be used for the version of the build. 10 | # If unset, determine a reasonable version identifier for current current commit 11 | # based on the closest vX.Y.Z tag in the branch's history. For example: v10.4.0-6-ged57c1e 12 | # --tags :: consider all tags, not only annotated tags 13 | # --match :: a regex to select a tag that matches our version number tag scheme 14 | CIRCLE_TAG ?= $(shell git describe --always --tags --match "v[0-9]*" HEAD) 15 | 16 | .PHONY: test 17 | #: run the tests! 18 | test: 19 | ifeq (, $(shell which gotestsum)) 20 | @echo " ***" 21 | @echo "Running with standard go test because gotestsum was not found on PATH. Consider installing gotestsum for friendlier test output!" 22 | @echo " ***" 23 | go test -race ./... 24 | else 25 | gotestsum --junitfile unit-tests.xml --format testname -- -race ./... 26 | endif 27 | 28 | .PHONY: version 29 | version: 30 | @echo $(CIRCLE_TAG) 31 | 32 | # target directory for artifact builds 33 | ARTIFACT_DIR := artifacts 34 | $(ARTIFACT_DIR): 35 | mkdir -p $@ 36 | 37 | BUILD_DIR := $(ARTIFACT_DIR)/$(GOOS) 38 | $(BUILD_DIR): 39 | mkdir -p $@ 40 | 41 | # List of the Go source files; the build target will then know if these are newer than an executable present. 42 | GO_SOURCES := go.mod go.sum $(wildcard *.go) $(wildcard */*.go) 43 | ldflags := "-X main.version=$(CIRCLE_TAG)" 44 | 45 | $(BUILD_DIR)/honeycomb-lambda-extension-arm64: $(GO_SOURCES) | $(BUILD_DIR) 46 | @echo "\n*** Building honeycomb-lambda-extension for ${GOOS}/arm64" 47 | GOOS=${GOOS} GOARCH=arm64 go build -ldflags ${ldflags} -o $@ . 48 | 49 | $(BUILD_DIR)/honeycomb-lambda-extension-x86_64: $(GO_SOURCES) | $(BUILD_DIR) 50 | @echo "\n*** Building honeycomb-lambda-extension for ${GOOS}/x86_64" 51 | GOOS=${GOOS} GOARCH=amd64 go build -ldflags ${ldflags} -o $@ . 52 | 53 | .PHONY: build 54 | #: build the executables 55 | build: $(BUILD_DIR)/honeycomb-lambda-extension-arm64 $(BUILD_DIR)/honeycomb-lambda-extension-x86_64 56 | 57 | ### ZIPs for layer publishing 58 | # 59 | # Linux is the only supported OS. 60 | # 61 | # The ZIP file for the content of a lambda layers a.k.a. extention MUST have: 62 | # * an extensions/ directory 63 | # * the executable that is the extension located within the extensions/ directory 64 | # 65 | # some of the Make automatic variables in use in these recipes: 66 | # $(@D) - the directory portion of the target, e.g. artifacts/linux/thingie.zip $(@D) == artifacts/linux 67 | # $(@F) - the file portion of the target, e.g. artifacts/linux/thingie.zip, $(@F) == thingie.zip 68 | # $< - the first prerequisite, in this case the executable being put into the zip file 69 | $(ARTIFACT_DIR)/linux/extension-arm64.zip: $(ARTIFACT_DIR)/linux/honeycomb-lambda-extension-arm64 70 | @echo "\n*** Packaging honeycomb-lambda-extension for linux into layer contents zipfile" 71 | rm -rf $(@D)/extensions 72 | mkdir -p $(@D)/extensions 73 | cp $< $(@D)/extensions 74 | cd $(@D) && zip --move --recurse-paths $(@F) extensions 75 | 76 | $(ARTIFACT_DIR)/linux/extension-x86_64.zip: $(ARTIFACT_DIR)/linux/honeycomb-lambda-extension-x86_64 77 | @echo "\n*** Packaging honeycomb-lambda-extension for linux into layer contents zipfile" 78 | rm -rf $(@D)/extensions 79 | mkdir -p $(@D)/extensions 80 | cp $< $(@D)/extensions 81 | cd $(@D) && zip --move --recurse-paths $(@F) extensions 82 | 83 | #: build the zipfiles destined to be published as layer contents (GOOS=linux only) 84 | ifeq ($(GOOS),linux) 85 | zips: $(ARTIFACT_DIR)/linux/extension-arm64.zip $(ARTIFACT_DIR)/linux/extension-x86_64.zip 86 | else 87 | zips: 88 | @echo "\n*** GOOS is set to ${GOOS}. Zips destined for publishing as a layer can only be for linux." 89 | exit 1 90 | endif 91 | 92 | .PHONY: update-licenses 93 | update-licenses: 94 | go install github.com/google/go-licenses@latest 95 | go-licenses save github.com/honeycombio/honeycomb-lambda-extension --save_path="./LICENSES" --force 96 | 97 | .PHONY: publish-sandbox 98 | # Ex: AWS_ARCH=arm64 AWS_REGION=us-east-1 make publish_sandbox 99 | # 100 | #: for serious, don't use this as-is for real publishing 101 | publish_sandbox: are_you_sure arch_required region_required zips 102 | @echo "\n*** Publishing honeycomb-lambda-extension-${AWS_ARCH} to ${AWS_REGION}" 103 | aws lambda publish-layer-version \ 104 | --layer-name honeycomb-lambda-extension-${AWS_ARCH} \ 105 | --region ${AWS_REGION} \ 106 | --compatible-architectures ${AWS_ARCH} \ 107 | --zip-file "fileb://${ARTIFACT_DIR}/linux/extension-${AWS_ARCH}.zip" \ 108 | --no-cli-pager 109 | 110 | #: clean up the workspace 111 | clean: 112 | rm -rf artifacts 113 | 114 | ### Utilities 115 | 116 | .PHONY: region_required 117 | region_required: 118 | @:$(call check_defined, AWS_REGION, the region to publish to) 119 | 120 | .PHONY: arch_required 121 | arch_required: 122 | @:$(call check_defined, AWS_ARCH, the architecture to publish) 123 | 124 | .PHONY: are_you_sure 125 | are_you_sure: 126 | @( read -p "Are you sure?!? [y/N]: " sure && case "$$sure" in [yY]) true;; *) false;; esac ) 127 | 128 | check_defined = \ 129 | $(strip $(foreach 1,$1, \ 130 | $(call __check_defined,$1,$(strip $(value 2))))) 131 | __check_defined = \ 132 | $(if $(value $1),, \ 133 | $(error Unset environment variable $1$(if $2, ($2))$(if $(value @), \ 134 | required by target `$@'))) 135 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-Present Honeycomb, Hound Technology, Inc. All Rights Reserved. 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 | -------------------------------------------------------------------------------- /OSSMETADATA: -------------------------------------------------------------------------------- 1 | osslifecycle=maintained 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # honeycomb-lambda-extension 2 | 3 | [![OSS Lifecycle](https://img.shields.io/osslifecycle/honeycombio/honeycomb-lambda-extension?color=success)](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md) 4 | [![CircleCI](https://circleci.com/gh/honeycombio/honeycomb-lambda-extension.svg?style=shield)](https://circleci.com/gh/honeycombio/honeycomb-lambda-extension) 5 | 6 | The honeycomb-lambda-extension allows you to send messages from your lambda 7 | function to Honeycomb by just writing JSON to stdout. The Honeycomb Lambda 8 | Extension will receive the messages your function sends to stdout and forward 9 | them to Honeycomb as events. 10 | 11 | The extension will also send platform events such as invocation start and 12 | shutdown events. 13 | 14 | ## Usage 15 | 16 | To use the honeycomb-lambda-extension with a lambda function, it must be configured as a layer. 17 | There are two variants of the extension available: one for `x86_64` architecture and one for `arm64` architecture. 18 | 19 | You can add the extension as a layer with the AWS CLI tool: 20 | 21 | ``` 22 | $ aws lambda update-code-configuration \ 23 | --function-name MyAwesomeFunction 24 | --layers "" 25 | ``` 26 | 27 | As of v11.0.0, the extension's layer version ARN follows the pattern below. ARNs for previous releases can be found in their [release notes](https://github.com/honeycombio/honeycomb-lambda-extension/releases). 28 | 29 | ``` 30 | # Layer Version ARN Pattern 31 | arn:aws:lambda::702835727665:layer:honeycomb-lambda-extension--:1 32 | ``` 33 | 34 | - `` - 35 | This must match the region of the Lambda function to which you are adding the extension. 36 | - `` - `x86_64` or `arm64` 37 | (*note*: Graviton2 `arm64` is supported in most, but not all regions. 38 | See [AWS Lambda Pricing](https://aws.amazon.com/lambda/pricing/) for which regions are supported.) 39 | - `` - 40 | The release version of the extension you wish to use with periods replaced by hyphens. 41 | For example: v11.0.0 -> v11-0-0. 42 | (Dots are not allowed characters in ARNs.) 43 | 44 | ### Configuration 45 | 46 | The extension is configurable via environment variables set for your lambda function. 47 | 48 | - `LIBHONEY_DATASET` - The Honeycomb dataset you would like events to be sent to. 49 | - `LIBHONEY_API_KEY` - Your Honeycomb API Key (also called Write Key). 50 | - `LIBHONEY_API_HOST` - Optional. Mostly used for testing purposes, or to be compatible with proxies. Defaults to https://api.honeycomb.io/. 51 | - `LOGS_API_DISABLE_PLATFORM_MSGS` - Optional. Set to "true" in order to disable "platform" messages from the logs API. 52 | - `HONEYCOMB_DEBUG` - Optional. Set to "true" to enable debug statements and troubleshoot issues. 53 | - `HONEYCOMB_BATCH_SEND_TIMEOUT` - Optional. 54 | The timeout for the complete HTTP request/response cycle for sending a batch of events Honeycomb. 55 | Default: 15s (15 seconds). 56 | Value should be given in a format parseable as a duration, such as "1m", "15s", or "750ms". 57 | There are other valid time units ("ns", "us"/"µs", "h"), but their use does not fit a timeout for HTTP connections made in the AWS Lambda compute environment. 58 | A batch send that times out has a single built-in retry; total time a lambda invocation may spend waiting is double this value. 59 | A very low duration may result in duplicate events, if Honeycomb data ingest is successful but slower than this timeout (rare, but possible). 60 | - `HONEYCOMB_CONNECT_TIMEOUT` - Optional. 61 | This timeout setting configures how long it can take to establish a TCP connection to Honeycomb. This setting is useful if there are ever connectivity issues, as it allows an upload requests to fail faster and not wait until the much longer batch send timeout is reached. 62 | Default: 3s (3 seconds). 63 | Value should be given in a format parseable as a duration, such as "1m", "15s", or "750ms". 64 | There are other valid time units ("ns", "us"/"µs", "h"), but their use does not fit a timeout for HTTP connections made in the AWS Lambda compute environment. 65 | 66 | ### Terraform Example 67 | 68 | If you're using an infrastructure as code tool such as [Terraform](https://www.terraform.io/) to manage your lambda functions, you can add this extension as a layer. 69 | 70 | ``` 71 | resource "aws_lambda_function" "extensions-demo-example-lambda-python" { 72 | function_name = "LambdaFunctionUsingHoneycombExtension" 73 | s3_bucket = "lambda-function-s3-bucket-name" 74 | s3_key = "lambda-functions-are-great.zip" 75 | handler = "handler.func" 76 | runtime = "python3.8" 77 | role = aws_iam_role.lambda_role.arn 78 | 79 | environment { 80 | variables = { 81 | LIBHONEY_API_KEY = "honeycomb-api-key", 82 | LIBHONEY_DATASET = "lambda-extension-test" 83 | LIBHONEY_API_HOST = "api.honeycomb.io" 84 | } 85 | } 86 | 87 | layers = [ 88 | "arn:aws:lambda::702835727665:layer:honeycomb-lambda-extension--:1" 89 | ] 90 | } 91 | ``` 92 | 93 | ## Self Hosting - Building & Deploying 94 | 95 | You can also deploy this extension as a layer in your own AWS account. 96 | 97 | ### Option 1: Publish the Honeycomb-built extension 98 | 99 | - Download the ZIP file for your target architecture from [the GitHub release](https://github.com/honeycombio/honeycomb-lambda-extension/releases). 100 | - Publish the layer your AWS account. 101 | 102 | ```shell 103 | $ aws lambda publish-layer-version \ 104 | --layer-name honeycomb-lambda-extension \ 105 | --region \ 106 | --compatible-architectures \ 107 | --zip-file "fileb://" 108 | ``` 109 | 110 | ### Option 2: Build and publish your own extension 111 | 112 | From a clone of this project: 113 | 114 | ```shell 115 | $ make zips 116 | $ aws lambda publish-layer-version \ 117 | --layer-name honeycomb-lambda-extension \ 118 | --region \ 119 | --compatible-architectures \ 120 | --zip-file "fileb://artifacts/linux/extension-.zip" 121 | ``` 122 | 123 | ## Updating AWS regions we publish to 124 | 125 | Use the [AWS Lambda pricing](https://aws.amazon.com/lambda/pricing/) page to get list of regions that support x86_64 and arm64. 126 | 127 | As of 2023-02-27, follow these instructions to more readily compare region names to region ids: 128 | 129 | - View HTML source, navigate to dropdowns, copy whole ul element for each platform and add to local file (eg regions-x86_64.txt) 130 | - Tidy up content to only keep the region ids 131 | - Sort the file alphabetically 132 | - `sort -n regions-x86_64.txt > regions-x86_64-sorted.txt` 133 | - Perform a diff on the two files 134 | - `diff --ignore-matching-lines --side-by-side regions-arm64-sorted.txt regions-x86_64-sorted.txt` 135 | - Update REGIONS_WITH_ARM (supports both x86_64 and arm64) and REGIONS_NO_ARM (only supports x86_64) in [publish.sh](./publish.sh) with derived sets 136 | - All regions should support x86_64 and a small subset will not support arm64 137 | - **Note**: the source sometimes shows all regions and should not be considered a reliable way to tell whether ARM is supported; this should be a spot check with the dropdown provided. 138 | 139 | NOTE: We need to opt-in to a new region before we can publish to it. 140 | The [Regions and zones](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) page shows if a region requires opt-in. 141 | 142 | ## Contributions 143 | 144 | Features, bug fixes and other changes to the extension are gladly accepted. Please open issues or a pull request with your change. Remember to add your name to the CONTRIBUTORS file! 145 | 146 | All contributions will be released under the Apache License 2.0. 147 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Creating a new release 2 | 3 | 1. In a working copy of this repo, run `make update-licenses`. 4 | - We use [go-licenses](https://github.com/google/go-licenses) to ensure all project dependency licenses are correctly represented in this repository. 5 | - Assess any changes or additions to the contents of the `./LICENSES/` directory for dependencies that are licensed in a way we cannot redistribute. 6 | - If all is OK for redistribution, open a PR with the updates, review, and merge that before proceeding with the rest of the release steps. 7 | 1. Draft a docs PR for this release. 8 | 1. Update `CHANGELOG.md` with the changes since the last release. 9 | 1. Commit changes, push, and open a release preparation PR for review. 10 | 1. Once the pull request is merged, fetch the updated main branch. 11 | 1. Apply a tag for the new version on the merged commit (e.g. `git tag -a v2.3.1 -m "v2.3.1"`) 12 | 1. Push the tag upstream to kick off the release pipeline in CI (e.g. `git push origin v2.3.1`). This will create a draft GitHub release with build artifacts and will publish the new layer version in AWS. 13 | 1. Craft a release.json for this release. Most of the content for a `release.json` appears in the output of the publish_aws CI job. 14 | 1. Edit the draft GitHub release: 15 | - Click the Generate Release Notes button and double-check the content against the CHANGELOG. 16 | - Attach the updated `release.json` to the release as a "binary". 17 | 1. Return to the docs PR and update `data/projects/honeycomb-lambda-extension/release.json` and get a review! 18 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | This security policy applies to public projects under the [honeycombio organization][gh-organization] on GitHub. 4 | For security reports involving the services provided at `(ui|ui-eu|api|api-eu).honeycomb.io`, refer to the [Honeycomb Bug Bounty Program][bugbounty] for scope, expectations, and reporting procedures. 5 | 6 | ## Security/Bugfix Versions 7 | 8 | Security and bug fixes are generally provided only for the last minor version. 9 | Fixes are released either as part of the next minor version or as an on-demand patch version. 10 | 11 | Security fixes are given priority and might be enough to cause a new version to be released. 12 | 13 | ## Reporting a Vulnerability 14 | 15 | We encourage responsible disclosure of security vulnerabilities. 16 | If you find something suspicious, we encourage and appreciate your report! 17 | 18 | ### Ways to report 19 | 20 | In order for the vulnerability reports to reach maintainers as soon as possible, the preferred way is to use the "Report a vulnerability" button under the "Security" tab of the associated GitHub project. 21 | This creates a private communication channel between the reporter and the maintainers. 22 | 23 | If you are absolutely unable to or have strong reasons not to use GitHub's vulnerability reporting workflow, please reach out to the Honeycomb security team at [security@honeycomb.io](mailto:security@honeycomb.io). 24 | 25 | [gh-organization]: https://github.com/honeycombio 26 | [bugbounty]: https://www.honeycomb.io/bugbountyprogram 27 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # How to Get Help 2 | 3 | This project uses GitHub issues to track bugs, feature requests, and questions about using the project. Please search for existing issues before filing a new one. 4 | -------------------------------------------------------------------------------- /eventprocessor/eventprocessor.go: -------------------------------------------------------------------------------- 1 | package eventprocessor 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/honeycombio/honeycomb-lambda-extension/extension" 8 | "github.com/honeycombio/libhoney-go" 9 | "github.com/sirupsen/logrus" 10 | ) 11 | 12 | var ( 13 | log = logrus.WithFields(logrus.Fields{ 14 | "source": "hny-lambda-ext-eventprocessor", 15 | }) 16 | // ShutdownReasonFieldExtensionType is the field name for shutdown reason in shutdown reason event 17 | ShutdownReasonFieldExtensionType = "lambda_extension.type" 18 | // ShutdownReasonFieldRequestID is the field name used for request ID in shutdown reason event 19 | ShutdownReasonFieldRequestID = "requestId" 20 | // ShutdownReasonFieldInvokedFunctionARN is the field name used for function arn in shutdown reason event 21 | ShutdownReasonFieldInvokedFunctionARN = "invokedFunctionArn" 22 | ) 23 | 24 | // eventPoller is the interface that provides a next event for the event processor 25 | type eventPoller interface { 26 | NextEvent(ctx context.Context) (*extension.NextEventResponse, error) 27 | } 28 | 29 | // eventFlusher is the interface that provides a way to create new libhoney events and flush them 30 | type eventFlusher interface { 31 | NewEvent() *libhoney.Event 32 | Flush() 33 | } 34 | 35 | // Server represents a server that polls and processes Lambda extension events 36 | type Server struct { 37 | extensionClient eventPoller 38 | libhoneyClient eventFlusher 39 | invokedFunctionARN string 40 | lastRequestId string 41 | } 42 | 43 | // New takes an eventPoller and eventFlusher and returns a Server 44 | func New(extensionClient eventPoller, libhoneyClient eventFlusher) *Server { 45 | return &Server{ 46 | extensionClient: extensionClient, 47 | libhoneyClient: libhoneyClient, 48 | } 49 | } 50 | 51 | // Run executes an event loop to poll and process events from the Lambda extension API 52 | func (s *Server) Run(ctx context.Context, cancel context.CancelFunc) { 53 | for { 54 | select { 55 | case <-ctx.Done(): 56 | return 57 | default: 58 | s.pollEventAndProcess(ctx, cancel) 59 | } 60 | } 61 | } 62 | 63 | // pollEventAndProcess polls the Lambda extension next event API and processes a single event 64 | func (s *Server) pollEventAndProcess(ctx context.Context, cancel context.CancelFunc) { 65 | // Poll for event 66 | res, err := s.extensionClient.NextEvent(ctx) 67 | if err != nil { 68 | log.WithError(err).Warn("Error from NextEvent") 69 | return 70 | } 71 | 72 | // Ensure a flush happens and cancel is called if its a shutdown event 73 | defer func() { 74 | s.libhoneyClient.Flush() 75 | if res.EventType == extension.Shutdown { 76 | log.Warn("Received Lambda " + extension.Shutdown + ", events flushed and extension is shutting down.") 77 | cancel() 78 | } 79 | }() 80 | 81 | // Handles event types 82 | switch eventType := res.EventType; eventType { 83 | case extension.Invoke: 84 | log.Debug("Received INVOKE event.") 85 | s.lastRequestId = res.RequestID 86 | s.invokedFunctionARN = res.InvokedFunctionARN 87 | case extension.Shutdown: 88 | log.Debug("Received SHUTDOWN event.") 89 | if res.ShutdownReason != extension.ShutdownReasonSpindown && s.lastRequestId != "" { 90 | log.WithField("res.ShutdownReason", res.ShutdownReason).Debug("Sending shutdown reason") 91 | s.sendShutdownReason(res.ShutdownReason) 92 | } 93 | default: 94 | log.WithField("res", res).Debug("Received unknown event") 95 | } 96 | } 97 | 98 | // sendShutdownReason sends and flushes an event with the shutdown reason. The last 99 | // request ID and function ARN will also be include in the generated event. 100 | func (s *Server) sendShutdownReason(shutdownReason extension.ShutdownReason) { 101 | ev := s.libhoneyClient.NewEvent() 102 | ev.AddField(ShutdownReasonFieldExtensionType, fmt.Sprintf("platform.%s", shutdownReason)) 103 | ev.AddField(ShutdownReasonFieldRequestID, s.lastRequestId) 104 | ev.AddField(ShutdownReasonFieldInvokedFunctionARN, s.invokedFunctionARN) 105 | if err := ev.Send(); err != nil { 106 | log.WithError(err).Error("Unable to send event with shutdown reason") 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /eventprocessor/eventprocessor_test.go: -------------------------------------------------------------------------------- 1 | package eventprocessor_test 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "testing" 7 | 8 | "github.com/honeycombio/honeycomb-lambda-extension/eventprocessor" 9 | "github.com/honeycombio/honeycomb-lambda-extension/extension" 10 | "github.com/honeycombio/libhoney-go" 11 | "github.com/honeycombio/libhoney-go/transmission" 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func TestRun(t *testing.T) { 16 | tests := map[string]struct { 17 | eventPoller *fakeEventPoller 18 | eventFlusher *fakeEventFlusher 19 | expectedNextEventCount int 20 | expectedFlushCount int 21 | expectedShutdownEvent *transmission.Event 22 | }{ 23 | "a single invoke event type and normal shutdown": { 24 | eventPoller: &fakeEventPoller{nextEventResponses: []*extension.NextEventResponse{ 25 | { 26 | EventType: extension.Invoke, 27 | RequestID: "1", 28 | InvokedFunctionARN: "arn1", 29 | }, 30 | { 31 | EventType: extension.Shutdown, 32 | ShutdownReason: extension.ShutdownReasonSpindown, 33 | }, 34 | }}, 35 | eventFlusher: newFakeEventFlusher(), 36 | expectedNextEventCount: 2, 37 | expectedFlushCount: 2, 38 | expectedShutdownEvent: nil, 39 | }, 40 | "a single invoke event type and failure shutdown": { 41 | eventPoller: &fakeEventPoller{nextEventResponses: []*extension.NextEventResponse{ 42 | { 43 | EventType: extension.Invoke, 44 | RequestID: "1", 45 | InvokedFunctionARN: "arn1", 46 | }, 47 | { 48 | EventType: extension.Shutdown, 49 | ShutdownReason: extension.ShutdownReasonFailure, 50 | }, 51 | }}, 52 | eventFlusher: newFakeEventFlusher(), 53 | expectedNextEventCount: 2, 54 | expectedFlushCount: 2, 55 | expectedShutdownEvent: &transmission.Event{ 56 | Data: map[string]interface{}{ 57 | eventprocessor.ShutdownReasonFieldExtensionType: "platform.failure", 58 | eventprocessor.ShutdownReasonFieldRequestID: "1", 59 | eventprocessor.ShutdownReasonFieldInvokedFunctionARN: "arn1", 60 | }, 61 | }, 62 | }, 63 | "a single invoke event type and timeout shutdown": { 64 | eventPoller: &fakeEventPoller{nextEventResponses: []*extension.NextEventResponse{ 65 | { 66 | EventType: extension.Invoke, 67 | RequestID: "1", 68 | InvokedFunctionARN: "arn1", 69 | }, 70 | { 71 | EventType: extension.Shutdown, 72 | ShutdownReason: extension.ShutdownReasonTimeout, 73 | }, 74 | }}, 75 | eventFlusher: newFakeEventFlusher(), 76 | expectedNextEventCount: 2, 77 | expectedFlushCount: 2, 78 | expectedShutdownEvent: &transmission.Event{ 79 | Data: map[string]interface{}{ 80 | eventprocessor.ShutdownReasonFieldExtensionType: "platform.timeout", 81 | eventprocessor.ShutdownReasonFieldRequestID: "1", 82 | eventprocessor.ShutdownReasonFieldInvokedFunctionARN: "arn1", 83 | }, 84 | }, 85 | }, 86 | "a timeout shutdown (no last requestId)": { 87 | eventPoller: &fakeEventPoller{nextEventResponses: []*extension.NextEventResponse{ 88 | { 89 | EventType: extension.Shutdown, 90 | ShutdownReason: extension.ShutdownReasonTimeout, 91 | }, 92 | }}, 93 | eventFlusher: newFakeEventFlusher(), 94 | expectedNextEventCount: 1, 95 | expectedFlushCount: 1, 96 | expectedShutdownEvent: nil, 97 | }, 98 | "a single next event error, then normal invoke event type and normal shutdown": { 99 | eventPoller: &fakeEventPoller{ 100 | oneTimeError: errors.New("one time error"), 101 | nextEventResponses: []*extension.NextEventResponse{ 102 | { 103 | EventType: extension.Invoke, 104 | RequestID: "1", 105 | InvokedFunctionARN: "arn1", 106 | }, 107 | { 108 | EventType: extension.Shutdown, 109 | ShutdownReason: extension.ShutdownReasonSpindown, 110 | }, 111 | }, 112 | }, 113 | eventFlusher: newFakeEventFlusher(), 114 | expectedNextEventCount: 2, 115 | expectedFlushCount: 2, 116 | expectedShutdownEvent: nil, 117 | }, 118 | "an unknown event type and normal shutdown": { 119 | eventPoller: &fakeEventPoller{ 120 | nextEventResponses: []*extension.NextEventResponse{ 121 | { 122 | EventType: "unknown", 123 | }, 124 | { 125 | EventType: extension.Shutdown, 126 | ShutdownReason: extension.ShutdownReasonSpindown, 127 | }, 128 | }, 129 | }, 130 | eventFlusher: newFakeEventFlusher(), 131 | expectedNextEventCount: 2, 132 | expectedFlushCount: 2, 133 | expectedShutdownEvent: nil, 134 | }, 135 | } 136 | 137 | for name, tc := range tests { 138 | t.Run(name, func(t *testing.T) { 139 | processor := eventprocessor.New(tc.eventPoller, tc.eventFlusher) 140 | ctx, cancel := context.WithCancel(context.Background()) 141 | defer cancel() 142 | 143 | processor.Run(ctx, cancel) 144 | 145 | assert.Equal(t, tc.expectedNextEventCount, tc.eventPoller.nextEventCounter, "next event calls do not match") 146 | assert.Equal(t, tc.expectedFlushCount, tc.eventFlusher.mockSender.Flushed, "flush calls do not match") 147 | if tc.expectedShutdownEvent != nil { 148 | assert.Equal(t, tc.expectedShutdownEvent.Data, tc.eventFlusher.mockSender.Events()[0].Data, "shutdown event does not match") 149 | } 150 | }) 151 | } 152 | } 153 | 154 | // ########################################### 155 | // Test implementations 156 | // ########################################### 157 | 158 | type fakeEventPoller struct { 159 | oneTimeError error 160 | nextEventCounter int 161 | nextEventResponses []*extension.NextEventResponse 162 | } 163 | 164 | func (f *fakeEventPoller) NextEvent(ctx context.Context) (*extension.NextEventResponse, error) { 165 | if ctx.Err() != nil { 166 | return nil, ctx.Err() 167 | } 168 | if f.oneTimeError != nil { 169 | err := f.oneTimeError 170 | f.oneTimeError = nil 171 | return nil, err 172 | } 173 | resp := f.nextEventResponses[f.nextEventCounter] 174 | f.nextEventCounter++ 175 | return resp, nil 176 | } 177 | 178 | func newFakeEventFlusher() *fakeEventFlusher { 179 | mockSender := &transmission.MockSender{} 180 | libhoneyClient, _ := libhoney.NewClient(libhoney.ClientConfig{ 181 | APIKey: "unit-test-api-key", 182 | Dataset: "unit-test-dataset", 183 | Transmission: mockSender, 184 | }) 185 | return &fakeEventFlusher{ 186 | mockSender: mockSender, 187 | libhoneyClient: libhoneyClient, 188 | } 189 | } 190 | 191 | type fakeEventFlusher struct { 192 | libhoneyClient *libhoney.Client 193 | mockSender *transmission.MockSender 194 | } 195 | 196 | func (f *fakeEventFlusher) NewEvent() *libhoney.Event { 197 | return f.libhoneyClient.NewEvent() 198 | } 199 | 200 | func (f *fakeEventFlusher) Flush() { 201 | f.mockSender.Flush() 202 | } 203 | -------------------------------------------------------------------------------- /eventpublisher/eventpublisher.go: -------------------------------------------------------------------------------- 1 | package eventpublisher 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "net/http" 7 | 8 | "github.com/honeycombio/honeycomb-lambda-extension/extension" 9 | "github.com/honeycombio/libhoney-go" 10 | "github.com/honeycombio/libhoney-go/transmission" 11 | "github.com/sirupsen/logrus" 12 | ) 13 | 14 | var ( 15 | log = logrus.WithFields(logrus.Fields{ 16 | "source": "hny-lambda-ext-eventpublisher", 17 | }) 18 | ) 19 | 20 | // Client is an event publisher that is just a light wrapper around libhoney 21 | type Client struct { 22 | libhoneyClient *libhoney.Client 23 | } 24 | 25 | // New returns a configured Client 26 | func New(config extension.Config, version string) (*Client, error) { 27 | if config.APIKey == "" || config.Dataset == "" { 28 | log.Warnln("APIKey or Dataset not set, disabling libhoney") 29 | libhoneyClient, err := libhoney.NewClient(libhoney.ClientConfig{}) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &Client{libhoneyClient: libhoneyClient}, nil 34 | } 35 | 36 | // httpTransport uses settings from http.DefaultTransport as starting point, but 37 | // overrides the dialer connect timeout 38 | httpTransport := http.DefaultTransport.(*http.Transport).Clone() 39 | httpTransport.DialContext = (&net.Dialer{ 40 | Timeout: config.ConnectTimeout, 41 | }).DialContext 42 | 43 | libhoneyClient, err := libhoney.NewClient(libhoney.ClientConfig{ 44 | APIKey: config.APIKey, 45 | Dataset: config.Dataset, 46 | APIHost: config.APIHost, 47 | Transmission: &transmission.Honeycomb{ 48 | MaxBatchSize: libhoney.DefaultMaxBatchSize, 49 | BatchTimeout: libhoney.DefaultBatchTimeout, 50 | MaxConcurrentBatches: libhoney.DefaultMaxConcurrentBatches, 51 | PendingWorkCapacity: libhoney.DefaultPendingWorkCapacity, 52 | UserAgentAddition: fmt.Sprintf("honeycomb-lambda-extension/%s", version), 53 | EnableMsgpackEncoding: true, 54 | BatchSendTimeout: config.BatchSendTimeout, 55 | Transport: httpTransport, 56 | }, 57 | }) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | publisher := &Client{libhoneyClient: libhoneyClient} 63 | 64 | if config.Debug { 65 | go publisher.readResponses() 66 | } 67 | 68 | return publisher, nil 69 | } 70 | 71 | func (c *Client) NewEvent() *libhoney.Event { 72 | return c.libhoneyClient.NewEvent() 73 | } 74 | 75 | func (c *Client) Flush() { 76 | c.libhoneyClient.Flush() 77 | } 78 | 79 | func (c *Client) TxResponses() chan transmission.Response { 80 | return c.libhoneyClient.TxResponses() 81 | } 82 | 83 | // read batch send responses from Honeycomb and log success/failures 84 | func (c *Client) readResponses() { 85 | for r := range c.TxResponses() { 86 | var metadata string 87 | if r.Metadata != nil { 88 | metadata = fmt.Sprintf("%s", r.Metadata) 89 | } 90 | if r.StatusCode >= 200 && r.StatusCode < 300 { 91 | message := "Successfully sent event to Honeycomb" 92 | if metadata != "" { 93 | message += fmt.Sprintf(": %s", metadata) 94 | } 95 | log.Debugf("%s", message) 96 | } else if r.StatusCode == http.StatusUnauthorized { 97 | log.Debugf("Error sending event to honeycomb! The APIKey was rejected, please verify your APIKey. %s", metadata) 98 | } else { 99 | log.Debugf("Error sending event to Honeycomb! %s had code %d, err %v and response body %s", 100 | metadata, r.StatusCode, r.Err, r.Body) 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /eventpublisher/eventpublisher_test.go: -------------------------------------------------------------------------------- 1 | package eventpublisher 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net" 7 | "net/http" 8 | "net/http/httptest" 9 | "runtime" 10 | "sync/atomic" 11 | "syscall" 12 | "testing" 13 | "time" 14 | 15 | "github.com/honeycombio/honeycomb-lambda-extension/extension" 16 | "github.com/stretchr/testify/assert" 17 | ) 18 | 19 | func TestEventPublisherHappyPathSend(t *testing.T) { 20 | testHandler := &TestHandler{ 21 | sleep: 0, 22 | responseCode: 200, 23 | response: []byte(`[{"status":200}]`), 24 | } 25 | testServer := httptest.NewServer(testHandler) 26 | defer testServer.Close() 27 | 28 | testConfig := extension.Config{ 29 | APIKey: "test-api-key", 30 | Dataset: "test-dataset", 31 | APIHost: testServer.URL, 32 | } 33 | 34 | eventpublisherClient, err := New(testConfig, "test-version") 35 | assert.Nil(t, err, "unexpected error when creating client") 36 | 37 | err = sendTestEvent(eventpublisherClient) 38 | assert.Nil(t, err, "unexpected error sending test event") 39 | 40 | txResponse := <-eventpublisherClient.TxResponses() 41 | assert.Nil(t, txResponse.Err, "unexpected error in response") 42 | assert.Equal(t, 1, int(atomic.LoadInt64(&testHandler.callCount)), "expected a single client request") 43 | assert.Equal(t, 200, txResponse.StatusCode) 44 | } 45 | 46 | func TestEventPublisherBatchSendTimeout(t *testing.T) { 47 | testHandler := &TestHandler{ 48 | sleep: time.Millisecond * 50, 49 | responseCode: 200, 50 | response: []byte(`[{"status":200}]`), 51 | } 52 | testServer := httptest.NewServer(testHandler) 53 | defer testServer.Close() 54 | 55 | testConfig := extension.Config{ 56 | APIKey: "test-api-key", 57 | Dataset: "test-dataset", 58 | APIHost: testServer.URL, 59 | BatchSendTimeout: 10 * time.Millisecond, 60 | } 61 | 62 | eventpublisherClient, err := New(testConfig, "test-version") 63 | assert.Nil(t, err, "unexpected error when creating client") 64 | 65 | err = sendTestEvent(eventpublisherClient) 66 | assert.Nil(t, err, "unexpected error sending test event") 67 | 68 | txResponse := <-eventpublisherClient.TxResponses() 69 | assert.Equal(t, 2, int(atomic.LoadInt64(&testHandler.callCount)), "expected 2 requests due to retry") 70 | assert.NotNil(t, txResponse.Err, "expected error in response") 71 | txResponseErr, ok := txResponse.Err.(net.Error) 72 | assert.True(t, ok, "expected a net.Error but got %v", txResponseErr) 73 | assert.True(t, txResponseErr.Timeout(), "expected error to be a timeout") 74 | } 75 | 76 | func TestEventPublisherConnectTimeout(t *testing.T) { 77 | testHandler := &TestHandler{} 78 | testServer := httptest.NewServer(testHandler) 79 | testServer.Close() 80 | 81 | testConfig := extension.Config{ 82 | APIKey: "test-api-key", 83 | Dataset: "test-dataset", 84 | APIHost: testServer.URL, 85 | ConnectTimeout: 10 * time.Millisecond, 86 | } 87 | 88 | eventpublisherClient, err := New(testConfig, "test-version") 89 | assert.Nil(t, err, "unexpected error creating client") 90 | 91 | err = sendTestEvent(eventpublisherClient) 92 | assert.Nil(t, err, "unexpected error sending test event") 93 | 94 | txResponse := <-eventpublisherClient.TxResponses() 95 | assert.Equal(t, 0, int(atomic.LoadInt64(&testHandler.callCount)), "expected 0 requests as server was shutdown") 96 | assert.NotNil(t, txResponse.Err, "expected response to be an error") 97 | txResponseErr, ok := txResponse.Err.(net.Error) 98 | assert.True(t, ok, fmt.Sprintf("expected a net.Error but got %v", txResponseErr)) 99 | assert.ErrorIs(t, txResponseErr, syscall.ECONNREFUSED, 100 | fmt.Sprintf("expected connection refused error but got %v", txResponseErr)) 101 | } 102 | 103 | func TestEventPublisherUserAgent(t *testing.T) { 104 | testHandler := &TestHandler{ 105 | requestAssertions: func(r *http.Request) { 106 | assert.Contains(t, r.Header.Get("User-Agent"), "honeycomb-lambda-extension/a-test-version") 107 | assert.Contains(t, r.Header.Get("User-Agent"), runtime.GOARCH) 108 | }, 109 | } 110 | testServer := httptest.NewServer(testHandler) 111 | defer testServer.Close() 112 | 113 | testConfig := extension.Config{ 114 | APIKey: "test-api-key", 115 | Dataset: "test-dataset", 116 | APIHost: testServer.URL, 117 | } 118 | 119 | eventpublisherClient, err := New(testConfig, "a-test-version") 120 | assert.Nil(t, err, "unexpected error when creating client") 121 | 122 | err = sendTestEvent(eventpublisherClient) 123 | assert.Nil(t, err, "unexpected error sending test event") 124 | } 125 | 126 | // ########################################### 127 | // Test implementations 128 | // ########################################### 129 | 130 | // sendTestEvent creates a test event and flushes it 131 | func sendTestEvent(client *Client) error { 132 | ev := client.NewEvent() 133 | ev.Add(map[string]interface{}{ 134 | "duration_ms": 153.12, 135 | "method": "test", 136 | }) 137 | 138 | err := ev.Send() 139 | if err != nil { 140 | return err 141 | } 142 | 143 | client.Flush() 144 | return nil 145 | } 146 | 147 | // TestHandler is a handler used for mocking server responses for the underlying HTTP calls 148 | // made by libhoney-go 149 | type TestHandler struct { 150 | callCount int64 151 | sleep time.Duration 152 | requestAssertions func(r *http.Request) 153 | responseCode int 154 | response []byte 155 | } 156 | 157 | func (h *TestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 158 | atomic.AddInt64(&h.callCount, 1) 159 | 160 | if h.responseCode == 0 { 161 | h.responseCode = 200 162 | } 163 | 164 | if h.requestAssertions != nil { 165 | h.requestAssertions(r) 166 | } 167 | 168 | _, err := ioutil.ReadAll(r.Body) 169 | if err != nil { 170 | http.Error(w, "can't read body", http.StatusBadRequest) 171 | return 172 | } 173 | 174 | select { 175 | case <-time.After(h.sleep): 176 | w.WriteHeader(h.responseCode) 177 | w.Write(h.response) 178 | return 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /extension/client.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "net/http" 10 | "net/url" 11 | "path" 12 | "strings" 13 | 14 | logrus "github.com/sirupsen/logrus" 15 | ) 16 | 17 | // EventType represents the type of events received from /event/next 18 | type EventType string 19 | 20 | // ShutdownReason represents the reason for a shutdown event 21 | type ShutdownReason string 22 | 23 | const ( 24 | // Invoke is the lambda invoke event 25 | Invoke EventType = "INVOKE" 26 | // Shutdown is a shutdown event for the environment 27 | Shutdown EventType = "SHUTDOWN" 28 | // ShutdownReasonSpindown is a normal end to a function 29 | ShutdownReasonSpindown ShutdownReason = "spindown" 30 | // ShutdownReasonTimeout means the handler ran out of time 31 | ShutdownReasonTimeout ShutdownReason = "timeout" 32 | // ShutdownReasonFailure is any other shutdown type, such as out-of-memory 33 | ShutdownReasonFailure ShutdownReason = "failure" 34 | // extensionNameHeader identifies the extension when registering 35 | extensionNameHeader = "Lambda-Extension-Name" 36 | // extensionIdentifierHeader is a uuid that is required on subsequent requests 37 | extensionIdentifierHeader = "Lambda-Extension-Identifier" 38 | ) 39 | 40 | var ( 41 | // set up logging defaults for our own logging output 42 | log = logrus.WithFields(logrus.Fields{ 43 | "source": "hny-lambda-ext-client", 44 | }) 45 | ) 46 | 47 | // Client is used to communicate with the Extensions API 48 | type Client struct { 49 | extensionName string 50 | baseURL string 51 | httpClient *http.Client 52 | // ExtensionID must be sent with each subsequent request after registering 53 | ExtensionID string 54 | } 55 | 56 | // RegisterResponse is the body of the response for /register 57 | type RegisterResponse struct { 58 | FunctionName string `json:"functionName"` 59 | FunctionVersion string `json:"functionVersion"` 60 | Handler string `json:"handler"` 61 | } 62 | 63 | // Tracing is part of the response for /event/next 64 | type Tracing struct { 65 | Type string `json:"type"` 66 | Value string `json:"value"` 67 | } 68 | 69 | // NextEventResponse is the response for /event/next 70 | type NextEventResponse struct { 71 | EventType EventType `json:"eventType"` 72 | DeadlineMS int64 `json:"deadlineMs"` 73 | RequestID string `json:"requestId"` 74 | InvokedFunctionARN string `json:"invokedFunctionArn"` 75 | Tracing Tracing `json:"tracing"` 76 | ShutdownReason ShutdownReason `json:"shutdownReason,omitempty"` 77 | } 78 | 79 | // NewClient returns a new Lambda Extensions API client 80 | func NewClient(baseURL string, extensionName string) *Client { 81 | if !strings.HasPrefix(baseURL, "http") { 82 | baseURL = fmt.Sprintf("http://%s", baseURL) 83 | } 84 | baseURL = fmt.Sprintf("%s/2020-01-01/extension", baseURL) 85 | return &Client{ 86 | baseURL: baseURL, 87 | extensionName: extensionName, 88 | httpClient: &http.Client{}, 89 | } 90 | } 91 | 92 | // Register registers the extension with the Lambda Extensions API. This happens 93 | // during Extension Init. Each call must include the list of events in the body 94 | // and the extension name in the headers. 95 | func (c *Client) Register(ctx context.Context) (*RegisterResponse, error) { 96 | reqBody, err := json.Marshal(map[string]interface{}{ 97 | "events": []EventType{Invoke, Shutdown}, 98 | }) 99 | if err != nil { 100 | return nil, err 101 | } 102 | req, err := http.NewRequestWithContext(ctx, "POST", c.url("/register"), bytes.NewBuffer(reqBody)) 103 | if err != nil { 104 | return nil, err 105 | } 106 | req.Header.Set(extensionNameHeader, c.extensionName) 107 | res, err := c.httpClient.Do(req) 108 | if err != nil { 109 | return nil, err 110 | } 111 | if res.StatusCode != http.StatusOK { 112 | return nil, fmt.Errorf("register request failed with status %s", res.Status) 113 | } 114 | defer res.Body.Close() 115 | body, err := ioutil.ReadAll(res.Body) 116 | if err != nil { 117 | return nil, err 118 | } 119 | resp := RegisterResponse{} 120 | if err = json.Unmarshal(body, &resp); err != nil { 121 | return nil, err 122 | } 123 | c.ExtensionID = res.Header.Get("Lambda-Extension-Identifier") 124 | if len(c.ExtensionID) == 0 { 125 | log.Warn("No extension identifier returned in header") 126 | } 127 | return &resp, nil 128 | } 129 | 130 | // NextEvent blocks while long polling for the next lambda invoke or shutdown 131 | // By default, the Go HTTP client has no timeout, and in this case this is actually 132 | // the desired behavior to enable long polling of the Extensions API. 133 | func (c *Client) NextEvent(ctx context.Context) (*NextEventResponse, error) { 134 | httpReq, err := http.NewRequestWithContext(ctx, "GET", c.url("/event/next"), nil) 135 | if err != nil { 136 | return nil, err 137 | } 138 | httpReq.Header.Set(extensionIdentifierHeader, c.ExtensionID) 139 | httpRes, err := c.httpClient.Do(httpReq) 140 | if err != nil { 141 | return nil, err 142 | } 143 | defer httpRes.Body.Close() 144 | if httpRes.StatusCode != http.StatusOK { 145 | return nil, fmt.Errorf("request failed with status %s", httpRes.Status) 146 | } 147 | body, err := ioutil.ReadAll(httpRes.Body) 148 | if err != nil { 149 | return nil, err 150 | } 151 | res := NextEventResponse{} 152 | err = json.Unmarshal(body, &res) 153 | if err != nil { 154 | return nil, err 155 | } 156 | return &res, nil 157 | } 158 | 159 | // url is a helper function to build urls out of relative paths 160 | func (c *Client) url(requestPath string) string { 161 | newURL, err := url.Parse(c.baseURL) 162 | if err != nil { 163 | return fmt.Sprintf("%s%s", c.baseURL, requestPath) 164 | } 165 | newURL.Path = path.Join(newURL.Path, requestPath) 166 | return newURL.String() 167 | } 168 | -------------------------------------------------------------------------------- /extension/client_test.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "io/ioutil" 7 | "net/http" 8 | "net/http/httptest" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | var ( 15 | testName = "test-extension" 16 | testIdentifier = "test-identifier" 17 | testFunctionName = "ThisIsAFunction" 18 | testFunctionVersion = "$LATEST" 19 | testFunctionHandler = "handler.test" 20 | 21 | testDeadlineMS = 676051 22 | testRequestID = "3da1f2dc-3222-475e-9205-e2e6c6318895" 23 | testFunctionARN = "arn:aws:lambda:us-east-1:123456789012:function:ExtensionTest" 24 | testTracingType = "X-Amzn-Trace-Id" 25 | testTracingValue = "Root=1-5f35ae12-0c0fec141ab77a00bc047aa2;Parent=2be948a625588e32;Sampled=1" 26 | ) 27 | 28 | func RegisterServer(t *testing.T) *httptest.Server { 29 | 30 | fixtures := []struct { 31 | name string 32 | expected string 33 | actual func(r *http.Request) string 34 | }{ 35 | { 36 | name: "request path", 37 | expected: "/2020-01-01/extension/register", 38 | actual: func(r *http.Request) string { 39 | return r.URL.String() 40 | }, 41 | }, 42 | { 43 | name: "request header", 44 | expected: testName, 45 | actual: func(r *http.Request) string { 46 | return r.Header.Get(extensionNameHeader) 47 | }, 48 | }, 49 | } 50 | 51 | handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 52 | for _, tt := range fixtures { 53 | t.Run(tt.name, func(t *testing.T) { 54 | got := tt.actual(r) 55 | if tt.expected != got { 56 | t.Errorf("got: %#v\nwant: %#v", tt.expected, got) 57 | } 58 | }) 59 | } 60 | defer r.Body.Close() 61 | body, err := ioutil.ReadAll(r.Body) 62 | if err != nil { 63 | t.Error("Error reading POST body") 64 | } 65 | var req map[string][]EventType 66 | if err := json.Unmarshal(body, &req); err != nil { 67 | t.Errorf("Error unmarshaling body: %s: %s", body, err) 68 | } 69 | events, ok := req["events"] 70 | if !ok { 71 | t.Error("Expected result to include events") 72 | } 73 | if events[0] != Invoke { 74 | t.Errorf("Expected invoke, got: %#v", events[0]) 75 | } 76 | if events[1] != Shutdown { 77 | t.Errorf("Expected shutdown, got: %#v", events[1]) 78 | } 79 | resp := RegisterResponse{ 80 | FunctionName: testFunctionName, 81 | FunctionVersion: testFunctionVersion, 82 | Handler: testFunctionHandler, 83 | } 84 | b, err := json.Marshal(resp) 85 | if err != nil { 86 | t.Error("Could not marshal JSON") 87 | } 88 | w.Header().Set(extensionIdentifierHeader, testIdentifier) 89 | w.Write(b) 90 | }) 91 | 92 | return httptest.NewServer(handlerFunc) 93 | } 94 | 95 | func NextEventServer(t *testing.T, eventType EventType) *httptest.Server { 96 | handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 97 | resp := NextEventResponse{ 98 | EventType: eventType, 99 | DeadlineMS: int64(testDeadlineMS), 100 | RequestID: testRequestID, 101 | InvokedFunctionARN: testFunctionARN, 102 | Tracing: Tracing{ 103 | Type: testTracingType, 104 | Value: testTracingValue, 105 | }, 106 | } 107 | b, err := json.Marshal(resp) 108 | if err != nil { 109 | t.Error("Could not marshal json") 110 | } 111 | w.Write(b) 112 | }) 113 | return httptest.NewServer(handlerFunc) 114 | } 115 | 116 | func TestRegisterExtension(t *testing.T) { 117 | server := RegisterServer(t) 118 | defer server.Close() 119 | 120 | client := NewClient(server.URL, testName) 121 | ctx := context.TODO() 122 | resp, err := client.Register(ctx) 123 | 124 | if err != nil { 125 | t.Error(err) 126 | return 127 | } 128 | 129 | if resp == nil { 130 | t.Error("Unexpected response from register") 131 | return 132 | } 133 | 134 | assert.Equal(t, testFunctionName, resp.FunctionName) 135 | assert.Equal(t, testIdentifier, client.ExtensionID) 136 | } 137 | 138 | func TestNextEvent(t *testing.T) { 139 | server := NextEventServer(t, Invoke) 140 | defer server.Close() 141 | 142 | client := NewClient(server.URL, testName) 143 | ctx := context.TODO() 144 | if _, err := client.Register(ctx); err != nil { 145 | t.Error(err) 146 | } 147 | res, err := client.NextEvent(ctx) 148 | if err != nil { 149 | t.Error(err) 150 | } 151 | assert.Equal(t, Invoke, res.EventType) 152 | assert.Equal(t, "X-Amzn-Trace-Id", res.Tracing.Type) 153 | } 154 | 155 | func TestURL(t *testing.T) { 156 | client := NewClient("honeycomb.io/foo", testName) 157 | assert.Equal(t, "http://honeycomb.io/foo/2020-01-01/extension", client.baseURL) 158 | 159 | url := client.url("/foo/bar/baz") 160 | assert.Equal(t, "http://honeycomb.io/foo/2020-01-01/extension/foo/bar/baz", url) 161 | 162 | client = NewClient("https://mywebsite.com:9000", testName) 163 | 164 | assert.Equal(t, "https://mywebsite.com:9000/2020-01-01/extension", client.baseURL) 165 | assert.Equal(t, "https://mywebsite.com:9000/2020-01-01/extension/foo/bar", client.url("foo/bar")) 166 | } 167 | -------------------------------------------------------------------------------- /extension/config.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "encoding/base64" 5 | "os" 6 | "strconv" 7 | "time" 8 | 9 | "github.com/aws/aws-sdk-go/aws" 10 | "github.com/aws/aws-sdk-go/aws/session" 11 | "github.com/aws/aws-sdk-go/service/kms" 12 | ) 13 | 14 | const ( 15 | // default buffering options for logs api 16 | defaultTimeoutMS = 1000 17 | defaultMaxBytes = 262144 18 | defaultMaxItems = 1000 19 | 20 | // Waiting too long to send a batch of events can be 21 | // expensive in Lambda. It's reasonable to expect a 22 | // batch send to complete in this amount of time. 23 | defaultBatchSendTimeout = time.Second * 15 24 | 25 | // It's very generous to expect an HTTP connection to 26 | // to be established in this time. 27 | defaultConnectTimeout = time.Second * 3 28 | ) 29 | 30 | type Config struct { 31 | APIKey string // Honeycomb API key 32 | Dataset string // target dataset at Honeycomb to receive events 33 | APIHost string // Honeycomb API URL to which to send events 34 | Debug bool // Enable debug log output from the extension 35 | RuntimeAPI string // Set by AWS in extension environment. Expected to be hostname:port. 36 | LogsReceiverPort int 37 | LogsAPITimeoutMS int 38 | LogsAPIMaxBytes int 39 | LogsAPIMaxItems int 40 | LogsAPIDisablePlatformMessages bool 41 | 42 | // The start-to-finish timeout to send a batch of events to Honeycomb. 43 | BatchSendTimeout time.Duration 44 | 45 | // The timeout to establish an HTTP connection to Honeycomb API. This value ends 46 | // up being used as the Dial timeout for the underlying libhoney-go HTTP client. This setting 47 | // is critical to help reduce impact caused by connectivity issues as it allows us to 48 | // fail fast and not have to wait for the much longer HTTP client timeout to occur. 49 | ConnectTimeout time.Duration 50 | } 51 | 52 | // Returns a new Honeycomb extension config with values populated 53 | // from environment variables. 54 | func NewConfigFromEnvironment() Config { 55 | return Config{ 56 | APIKey: getApiKey(), 57 | Dataset: os.Getenv("LIBHONEY_DATASET"), 58 | APIHost: os.Getenv("LIBHONEY_API_HOST"), 59 | Debug: envOrElseBool("HONEYCOMB_DEBUG", false), 60 | RuntimeAPI: os.Getenv("AWS_LAMBDA_RUNTIME_API"), 61 | LogsReceiverPort: 3000, // a constant for now 62 | LogsAPITimeoutMS: envOrElseInt("LOGS_API_TIMEOUT_MS", defaultTimeoutMS), 63 | LogsAPIMaxBytes: envOrElseInt("LOGS_API_MAX_BYTES", defaultMaxBytes), 64 | LogsAPIMaxItems: envOrElseInt("LOGS_API_MAX_ITEMS", defaultMaxItems), 65 | LogsAPIDisablePlatformMessages: envOrElseBool("LOGS_API_DISABLE_PLATFORM_MSGS", false), 66 | BatchSendTimeout: envOrElseDuration("HONEYCOMB_BATCH_SEND_TIMEOUT", defaultBatchSendTimeout), 67 | ConnectTimeout: envOrElseDuration("HONEYCOMB_CONNECT_TIMEOUT", defaultConnectTimeout), 68 | } 69 | } 70 | 71 | // envOrElseInt retrieves an environment variable value by the given key, 72 | // return an integer based on that value. 73 | // 74 | // If env var cannot be found by the key or value fails to cast to an int, 75 | // return the given fallback integer. 76 | func envOrElseInt(key string, fallback int) int { 77 | if value, ok := os.LookupEnv(key); ok { 78 | v, err := strconv.Atoi(value) 79 | if err != nil { 80 | log.Warnf("%s was set to '%s', but failed to parse to an integer. Falling back to default of %d.", key, value, fallback) 81 | return fallback 82 | } 83 | return v 84 | } 85 | return fallback 86 | } 87 | 88 | // envOrElseBool retrieves an environment variable value by the given key, 89 | // return a boolean based on that value. 90 | // 91 | // If env var cannot be found by the key or value fails to cast to a bool, 92 | // return the given fallback boolean. 93 | func envOrElseBool(key string, fallback bool) bool { 94 | if value, ok := os.LookupEnv(key); ok { 95 | v, err := strconv.ParseBool(value) 96 | if err != nil { 97 | log.Warnf("%s was set to '%s', but failed to parse to true or false. Falling back to default of %t.", key, value, fallback) 98 | return fallback 99 | } 100 | return v 101 | } 102 | return fallback 103 | } 104 | 105 | // envOrElseDuration retrieves an environment variable value by the given key, 106 | // return the result of parsing the value as a duration. 107 | // 108 | // If value is an integer instead of a duration, 109 | // return a duration assuming seconds as the unit. 110 | // 111 | // If env var cannot be found by the key, 112 | // or the value fails to parse as a duration or integer, 113 | // or the result is a duration of 0, 114 | // return the given fallback duration. 115 | func envOrElseDuration(key string, fallback time.Duration) time.Duration { 116 | value, ok := os.LookupEnv(key) 117 | if ok { 118 | dur, err := time.ParseDuration(value) 119 | if err == nil { 120 | if dur == 0 { 121 | log.Warnf("%s was set to '%s', which is an unusable duration for the extension. Falling back to default of %s.", key, value, fallback) 122 | return fallback 123 | } else { 124 | return dur 125 | } 126 | } 127 | 128 | v, err := strconv.Atoi(value) 129 | if err == nil { 130 | dur_s := time.Duration(v) * time.Second 131 | log.Warnf("%s was set to %d (an integer, not a duration). Assuming 'seconds' as unit, resulting in %s.", key, v, dur_s) 132 | return dur_s 133 | } 134 | log.Warnf("%s was set to '%s', but failed to parse to a duration. Falling back to default of %s.", key, value, fallback) 135 | } 136 | return fallback 137 | } 138 | 139 | // kmsDecryptFunc is a function that can be mocked in tests to 140 | // avoid making actual calls to AWS. 141 | var kmsDecryptFunc = func(svc *kms.KMS, input *kms.DecryptInput) (*kms.DecryptOutput, error) { 142 | return svc.Decrypt(input) 143 | } 144 | 145 | // getApiKey checks if KMS_KEY_ID is supplied, and if it is, we assume we are dealing with a KMS-encrypted API key. 146 | // If KMS_KEY_ID is supplied, we must also have a base64 encrypted LIBHONEY_API_KEY. 147 | func getApiKey() string { 148 | apiKey := os.Getenv("LIBHONEY_API_KEY") 149 | if apiKey == "" { 150 | log.Error("LIBHONEY_API_KEY is not set. Please set it to your Honeycomb API key.") 151 | return "" 152 | } 153 | 154 | kmsKeyId := os.Getenv("KMS_KEY_ID") 155 | if kmsKeyId == "" { 156 | // return unencrypted API Key, no KMS decryption needed 157 | return apiKey 158 | } 159 | 160 | // decrypt the API key using KMS 161 | kmsSession := session.Must(session.NewSession(&aws.Config{ 162 | Region: aws.String(os.Getenv("AWS_REGION")), 163 | })) 164 | 165 | config := &aws.Config{} 166 | svc := kms.New(kmsSession, config) 167 | ciphertext, err := base64.StdEncoding.DecodeString(apiKey) 168 | if err != nil { 169 | log.Errorf("unable to decode ciphertext in Honeycomb API key: %v", err) 170 | return "" 171 | } 172 | 173 | resp, err := kmsDecryptFunc(svc, &kms.DecryptInput{ 174 | CiphertextBlob: ciphertext, 175 | }) 176 | 177 | if err != nil { 178 | log.Errorf("Failed to decrypt Honeycomb API key: %v", err) 179 | return "" 180 | } 181 | return string(resp.Plaintext) 182 | } 183 | -------------------------------------------------------------------------------- /extension/config_test.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "encoding/base64" 5 | "testing" 6 | "time" 7 | 8 | "github.com/aws/aws-sdk-go/service/kms" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func Test_EnvOrElseInt(t *testing.T) { 13 | aDefaultInt := 42 14 | testCases := []struct { 15 | desc string 16 | envValue string 17 | expectedValue int 18 | }{ 19 | { 20 | desc: "default", 21 | envValue: "not-set", 22 | expectedValue: aDefaultInt, 23 | }, 24 | { 25 | desc: "set by user: integer", 26 | envValue: "23", 27 | expectedValue: 23, 28 | }, 29 | { 30 | desc: "bad input: words", 31 | envValue: "twenty-three", 32 | expectedValue: aDefaultInt, 33 | }, 34 | { 35 | desc: "bad input: unicode", 36 | envValue: "🤷", 37 | expectedValue: aDefaultInt, 38 | }, 39 | } 40 | for _, tC := range testCases { 41 | t.Run(tC.desc, func(t *testing.T) { 42 | if tC.envValue != "not-set" { 43 | t.Setenv("SOME_TEST_ENV_VAR", tC.envValue) 44 | } 45 | assert.Equal(t, tC.expectedValue, envOrElseInt("SOME_TEST_ENV_VAR", aDefaultInt)) 46 | }) 47 | } 48 | } 49 | 50 | func Test_EnvOrElseBool(t *testing.T) { 51 | aDefaultBool := false 52 | testCases := []struct { 53 | desc string 54 | envValue string 55 | expectedValue bool 56 | }{ 57 | { 58 | desc: "default", 59 | envValue: "not-set", 60 | expectedValue: aDefaultBool, 61 | }, 62 | { 63 | desc: "set by user: true", 64 | envValue: "true", 65 | expectedValue: true, 66 | }, 67 | { 68 | desc: "set by user: false", 69 | envValue: "false", 70 | expectedValue: false, 71 | }, 72 | { 73 | desc: "bad input: non-bool words", 74 | envValue: "verily yes", 75 | expectedValue: aDefaultBool, 76 | }, 77 | { 78 | desc: "bad input: unicode", 79 | envValue: "🤷", 80 | expectedValue: aDefaultBool, 81 | }, 82 | } 83 | for _, tC := range testCases { 84 | t.Run(tC.desc, func(t *testing.T) { 85 | if tC.envValue != "not-set" { 86 | t.Setenv("SOME_TEST_ENV_VAR", tC.envValue) 87 | } 88 | assert.Equal(t, tC.expectedValue, envOrElseBool("SOME_TEST_ENV_VAR", aDefaultBool)) 89 | }) 90 | } 91 | } 92 | 93 | func Test_EnvOrElseDuration(t *testing.T) { 94 | aDefaultDuration := 42 * time.Second 95 | testCases := []struct { 96 | desc string 97 | envValue string 98 | expectedValue time.Duration 99 | }{ 100 | { 101 | desc: "default", 102 | envValue: "not-set", 103 | expectedValue: aDefaultDuration, 104 | }, 105 | { 106 | desc: "set by user: duration seconds", 107 | envValue: "9s", 108 | expectedValue: 9 * time.Second, 109 | }, 110 | { 111 | desc: "set by user: duration milliseconds", 112 | envValue: "900ms", 113 | expectedValue: 900 * time.Millisecond, 114 | }, 115 | { 116 | desc: "set by user: duration zero", 117 | envValue: "0s", 118 | expectedValue: aDefaultDuration, 119 | }, 120 | { 121 | desc: "set by user: integer", 122 | envValue: "23", 123 | expectedValue: 23 * time.Second, 124 | }, 125 | { 126 | desc: "set by user: integer zero", 127 | envValue: "0", 128 | expectedValue: aDefaultDuration, 129 | }, 130 | { 131 | desc: "bad input: words", 132 | envValue: "forty-two", 133 | expectedValue: aDefaultDuration, 134 | }, 135 | { 136 | desc: "bad input: unicode", 137 | envValue: "🤷", 138 | expectedValue: aDefaultDuration, 139 | }, 140 | } 141 | for _, tC := range testCases { 142 | t.Run(tC.desc, func(t *testing.T) { 143 | if tC.envValue != "not-set" { 144 | t.Setenv("SOME_TEST_ENV_VAR", tC.envValue) 145 | } 146 | assert.Equal(t, tC.expectedValue, envOrElseDuration("SOME_TEST_ENV_VAR", aDefaultDuration)) 147 | }) 148 | } 149 | } 150 | 151 | func Test_GetApiKey(t *testing.T) { 152 | originalApiKey := "test-api-key" 153 | encodedApiKey := base64.StdEncoding.EncodeToString([]byte(originalApiKey)) 154 | assert.Equal(t, "dGVzdC1hcGkta2V5", encodedApiKey) 155 | 156 | originalKmsDecryptFunc := kmsDecryptFunc 157 | defer func() { 158 | kmsDecryptFunc = originalKmsDecryptFunc 159 | }() 160 | 161 | testCases := []struct { 162 | desc string 163 | envSetup func(t *testing.T) 164 | mockSetup func(t *testing.T) 165 | expectedValue string 166 | expectError bool 167 | }{ 168 | { 169 | desc: "regular libhoney api key", 170 | envSetup: func(t *testing.T) { 171 | t.Setenv("LIBHONEY_API_KEY", originalApiKey) 172 | t.Setenv("KMS_KEY_ID", "") 173 | }, 174 | expectedValue: originalApiKey, 175 | expectError: false, 176 | }, 177 | { 178 | desc: "kms-encrypted api key", 179 | envSetup: func(t *testing.T) { 180 | t.Setenv("LIBHONEY_API_KEY", encodedApiKey) 181 | t.Setenv("KMS_KEY_ID", "some-key-id") 182 | }, 183 | mockSetup: func(t *testing.T) { 184 | kmsDecryptFunc = func(svc *kms.KMS, input *kms.DecryptInput) (*kms.DecryptOutput, error) { 185 | return &kms.DecryptOutput{ 186 | Plaintext: []byte(originalApiKey), 187 | }, nil 188 | } 189 | }, 190 | expectedValue: originalApiKey, 191 | expectError: false, 192 | }, 193 | { 194 | desc: "invalid base64 in encrypted api key", 195 | envSetup: func(t *testing.T) { 196 | t.Setenv("LIBHONEY_API_KEY", "not-valid-base64") 197 | t.Setenv("KMS_KEY_ID", "some-key-id") 198 | }, 199 | expectError: true, 200 | }, 201 | { 202 | desc: "KMS_KEY_ID set but not LIBHONEY_API_KEY", 203 | envSetup: func(t *testing.T) { 204 | t.Setenv("LIBHONEY_API_KEY", "") 205 | t.Setenv("KMS_KEY_ID", "some-key-id") 206 | }, 207 | expectError: true, 208 | }, 209 | { 210 | desc: "neither LIBHONEY_API_KEY or KMS_KEY_ID set", 211 | envSetup: func(t *testing.T) { 212 | t.Setenv("LIBHONEY_API_KEY", "") 213 | t.Setenv("KMS_KEY_ID", "") 214 | }, 215 | expectError: true, 216 | }, 217 | } 218 | 219 | for _, tC := range testCases { 220 | t.Run(tC.desc, func(t *testing.T) { 221 | tC.envSetup(t) 222 | if tC.mockSetup != nil { 223 | tC.mockSetup(t) 224 | } 225 | apiKey := getApiKey() 226 | if tC.expectError { 227 | assert.Empty(t, apiKey, "Expected empty API key due to error condition") 228 | } else { 229 | assert.Equal(t, tC.expectedValue, apiKey) 230 | } 231 | }) 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/honeycombio/honeycomb-lambda-extension 2 | 3 | go 1.24 4 | 5 | require ( 6 | github.com/honeycombio/libhoney-go v1.25.0 7 | github.com/sirupsen/logrus v1.9.3 8 | github.com/stretchr/testify v1.10.0 9 | ) 10 | 11 | require github.com/jmespath/go-jmespath v0.4.0 // indirect 12 | 13 | require ( 14 | github.com/aws/aws-sdk-go v1.55.7 15 | github.com/davecgh/go-spew v1.1.1 // indirect 16 | github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect 17 | github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 // indirect 18 | github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 // indirect 19 | github.com/klauspost/compress v1.18.0 // indirect 20 | github.com/kr/pretty v0.1.0 // indirect 21 | github.com/pmezard/go-difflib v1.0.0 // indirect 22 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 23 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 24 | golang.org/x/sys v0.32.0 // indirect 25 | gopkg.in/alexcesaro/statsd.v2 v2.0.0 // indirect 26 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 27 | gopkg.in/yaml.v3 v3.0.1 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY= 2 | github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= 3 | github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= 4 | github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= 9 | github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= 10 | github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= 11 | github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= 12 | github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg= 13 | github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01/go.mod h1:ypD5nozFk9vcGw1ATYefw6jHe/jZP++Z15/+VTMcWhc= 14 | github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8= 15 | github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52/go.mod h1:yIquW87NGRw1FU5p5lEkpnt/QxoH5uPAOUlOVkAUuMg= 16 | github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= 17 | github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= 18 | github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= 19 | github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= 20 | github.com/honeycombio/libhoney-go v1.25.0 h1:r33tlX90HtafK0bgRcjfNnsrJ9ZMTKuI/1DYaOFCc1o= 21 | github.com/honeycombio/libhoney-go v1.25.0/go.mod h1:Fc0HjqlwYf5xy6H34EItpOverAGbCixnYOX3YTUQovg= 22 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 23 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 24 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 25 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 26 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= 27 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 28 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 29 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 30 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 31 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 32 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 33 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 34 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 35 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 36 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 37 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 38 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 39 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 40 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 41 | github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= 42 | github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= 43 | github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= 44 | github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= 45 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 46 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 47 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 48 | gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc= 49 | gopkg.in/alexcesaro/statsd.v2 v2.0.0/go.mod h1:i0ubccKGzBVNBpdGV5MocxyA/XlLUJzA7SLonnE4drU= 50 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 51 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 52 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 53 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 54 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 55 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 56 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 57 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 58 | -------------------------------------------------------------------------------- /logsapi/client.go: -------------------------------------------------------------------------------- 1 | package logsapi 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "net/http" 10 | "net/url" 11 | "path" 12 | "strings" 13 | 14 | "github.com/honeycombio/honeycomb-lambda-extension/extension" 15 | ) 16 | 17 | // Protocol represents the protocol that this extension should receive logs by 18 | type Protocol string 19 | 20 | // LogType represents the types of log messages that are supported by the logs API 21 | type LogType string 22 | 23 | const ( 24 | // Local hostname according to process running in extension env 25 | localHostname = "sandbox" 26 | 27 | // HTTPProtocol is the protocol that we receive logs over 28 | HTTPProtocol Protocol = "HTTP" 29 | 30 | // PlatformLog events originate from the Lambda Runtime 31 | PlatformLog LogType = "platform" 32 | // FunctionLog events originate from Lambda Functions 33 | FunctionLog LogType = "function" 34 | 35 | // extensionIdentifierHeader is used to pass a generated UUID to calls to the API 36 | extensionIdentifierHeader = "Lambda-Extension-Identifier" 37 | ) 38 | 39 | // Destination is where the runtime should send logs to 40 | type Destination struct { 41 | Protocol Protocol `json:"protocol"` 42 | URI string `json:"URI"` 43 | } 44 | 45 | // BufferingOptions contains buffering configuration options for the lambda platform 46 | type BufferingOptions struct { 47 | TimeoutMS uint `json:"timeoutMs"` 48 | MaxBytes uint64 `json:"maxBytes"` 49 | MaxItems uint64 `json:"maxItems"` 50 | } 51 | 52 | // Client is used to communicate with the Logs API 53 | type Client struct { 54 | baseURL string 55 | httpClient *http.Client 56 | destinationPort int 57 | bufferingOptions BufferingOptions 58 | ExtensionID string 59 | } 60 | 61 | // SubscribeRequest is the request to /logs 62 | type SubscribeRequest struct { 63 | Dest Destination `json:"destination"` 64 | Types []LogType `json:"types"` 65 | Buffering BufferingOptions `json:"buffering"` 66 | } 67 | 68 | // SubscribeResponse is the response from /logs subscribe message 69 | type SubscribeResponse struct { 70 | Message string 71 | } 72 | 73 | // Subscribe wraps the logic of creating a client for the AWS Lambda Logs API 74 | // and using the client to subscribe the extension to the configured log type streams. 75 | func Subscribe(ctx context.Context, config extension.Config, extensionID string) (*SubscribeResponse, error) { 76 | // create logs api client 77 | logsClient := newClient(config.RuntimeAPI, config.LogsReceiverPort, BufferingOptions{ 78 | TimeoutMS: uint(config.LogsAPITimeoutMS), 79 | MaxBytes: uint64(config.LogsAPIMaxBytes), 80 | MaxItems: uint64(config.LogsAPIMaxItems), 81 | }) 82 | 83 | var logTypes []LogType 84 | disablePlatformMsg := config.LogsAPIDisablePlatformMessages 85 | 86 | if disablePlatformMsg { 87 | logTypes = []LogType{FunctionLog} 88 | } else { 89 | logTypes = []LogType{PlatformLog, FunctionLog} 90 | } 91 | 92 | return logsClient.subscribeToLogTypes(ctx, extensionID, logTypes) 93 | } 94 | 95 | // newClient returns a new Lambda Logs API client 96 | func newClient(baseURL string, port int, bufferingOpts BufferingOptions) *Client { 97 | if !strings.HasPrefix(baseURL, "http") { 98 | baseURL = fmt.Sprintf("http://%s", baseURL) 99 | } 100 | baseURL = fmt.Sprintf("%s/2020-08-15", baseURL) 101 | return &Client{ 102 | baseURL: baseURL, 103 | httpClient: &http.Client{}, 104 | destinationPort: port, 105 | bufferingOptions: bufferingOpts, 106 | } 107 | } 108 | 109 | // subscribeToLogTypes will subscribe to event streams sent 110 | // from the Logs API of the given log types. 111 | func (c *Client) subscribeToLogTypes(ctx context.Context, extensionID string, types []LogType) (*SubscribeResponse, error) { 112 | subscribe := SubscribeRequest{ 113 | Dest: Destination{ 114 | Protocol: HTTPProtocol, 115 | URI: fmt.Sprintf("http://%s:%d", localHostname, c.destinationPort), 116 | }, 117 | Types: types, 118 | Buffering: c.bufferingOptions, 119 | } 120 | reqBody, err := json.Marshal(subscribe) 121 | if err != nil { 122 | return nil, err 123 | } 124 | httpReq, err := http.NewRequestWithContext(ctx, "PUT", c.url("/logs"), bytes.NewBuffer(reqBody)) 125 | if err != nil { 126 | return nil, err 127 | } 128 | httpReq.Header.Set(extensionIdentifierHeader, extensionID) 129 | httpRes, err := c.httpClient.Do(httpReq) 130 | if err != nil { 131 | return nil, err 132 | } 133 | if httpRes.StatusCode >= 400 { 134 | return nil, fmt.Errorf("request failed with status %s", httpRes.Status) 135 | } 136 | defer httpRes.Body.Close() 137 | body, err := ioutil.ReadAll(httpRes.Body) 138 | if err != nil { 139 | return nil, err 140 | } 141 | c.ExtensionID = httpRes.Header.Get(extensionIdentifierHeader) 142 | return &SubscribeResponse{ 143 | Message: string(body), 144 | }, nil 145 | } 146 | 147 | // url is a helper function to build urls out of relative paths 148 | func (c *Client) url(requestPath string) string { 149 | newURL, err := url.Parse(c.baseURL) 150 | if err != nil { 151 | return fmt.Sprintf("%s%s", c.baseURL, requestPath) 152 | } 153 | newURL.Path = path.Join(newURL.Path, requestPath) 154 | return newURL.String() 155 | } 156 | -------------------------------------------------------------------------------- /logsapi/client_test.go: -------------------------------------------------------------------------------- 1 | package logsapi 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | var ( 13 | destinationPort = 3000 14 | bufferingConfig = BufferingOptions{ 15 | TimeoutMS: 1000, 16 | MaxBytes: 262144, 17 | MaxItems: 1000, 18 | } 19 | testExtensionID = "extensionID" 20 | ) 21 | 22 | func SubscribeServer(t *testing.T) *httptest.Server { 23 | handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 24 | resp := SubscribeResponse{ 25 | Message: "OK", 26 | } 27 | w.Write([]byte(resp.Message)) 28 | }) 29 | 30 | return httptest.NewServer(handlerFunc) 31 | } 32 | 33 | func TestSubscribeLogs(t *testing.T) { 34 | server := SubscribeServer(t) 35 | defer server.Close() 36 | 37 | client := newClient(server.URL, destinationPort, bufferingConfig) 38 | ctx := context.TODO() 39 | 40 | resp, err := client.subscribeToLogTypes(ctx, testExtensionID, []LogType{PlatformLog, FunctionLog}) 41 | if err != nil { 42 | t.Error(err) 43 | } 44 | assert.Equal(t, "OK", resp.Message) 45 | } 46 | 47 | func TestURL(t *testing.T) { 48 | client := newClient("honeycomb.io/foo", 3000, BufferingOptions{}) 49 | assert.Equal(t, "http://honeycomb.io/foo/2020-08-15", client.baseURL) 50 | 51 | url := client.url("/foo/bar/baz") 52 | assert.Equal(t, "http://honeycomb.io/foo/2020-08-15/foo/bar/baz", url) 53 | 54 | client = newClient("https://mywebsite.com:9000", 3000, BufferingOptions{}) 55 | 56 | assert.Equal(t, "https://mywebsite.com:9000/2020-08-15", client.baseURL) 57 | assert.Equal(t, "https://mywebsite.com:9000/2020-08-15/foo/bar", client.url("foo/bar")) 58 | } 59 | -------------------------------------------------------------------------------- /logsapi/server.go: -------------------------------------------------------------------------------- 1 | package logsapi 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | 11 | libhoney "github.com/honeycombio/libhoney-go" 12 | logrus "github.com/sirupsen/logrus" 13 | ) 14 | 15 | // LogMessage is a message sent from the Logs API 16 | type LogMessage struct { 17 | Type string `json:"type"` 18 | Time string `json:"time"` 19 | Record interface{} `json:"record"` 20 | } 21 | 22 | type eventCreator interface { 23 | NewEvent() *libhoney.Event 24 | } 25 | 26 | var ( 27 | // set up logging defaults for our own logging output 28 | log = logrus.WithFields(logrus.Fields{ 29 | "source": "hny-lambda-ext-logsapi", 30 | }) 31 | ) 32 | 33 | // handler receives batches of log messages from the Lambda Logs API. Each 34 | // LogMessage is sent to Honeycomb as a separate event. 35 | func handler(client eventCreator) http.HandlerFunc { 36 | return func(w http.ResponseWriter, r *http.Request) { 37 | log.Debug("handler - log batch received") 38 | body, err := ioutil.ReadAll(r.Body) 39 | if err != nil { 40 | log.Warn("Error", err) 41 | return 42 | } 43 | defer r.Body.Close() 44 | 45 | // The Logs API will send batches of events as an array of JSON objects. 46 | // Each object will have time, type and record as the top-level keys. If 47 | // the log message is a function message, the record element will contain 48 | // whatever was emitted by the function to stdout. This could be a structured 49 | // log message (JSON) or a plain string. 50 | var logs []LogMessage 51 | err = json.Unmarshal(body, &logs) 52 | if err != nil { 53 | log.Warn("Could not unmarshal payload", err) 54 | return 55 | } 56 | 57 | // Iterate through the batch of log messages received. In the case of function 58 | // log messages, the Record field of the struct will be a string. That string 59 | // may contain string-encoded JSON (e.g. "{\"trace.trace_id\": \"1234\", ...}") 60 | // in which case, we will try to parse the JSON into a map[string]interface{} 61 | // and then add it to the Honeycomb event. If, for some reason, parsing the JSON 62 | // is impossible, then we just add the string as a field "record" in Honeycomb. 63 | // This is what will happen if the function emits plain, non-structured strings. 64 | for _, msg := range logs { 65 | event := client.NewEvent() 66 | event.AddField("lambda_extension.type", msg.Type) 67 | 68 | switch record := msg.Record.(type) { 69 | case string: 70 | // attempt to parse record as json 71 | var jsonRecord map[string]interface{} 72 | err := json.Unmarshal([]byte(record), &jsonRecord) 73 | if err != nil { 74 | // not JSON; we'll treat this log entry as a timestamped string 75 | event.Timestamp = parseMessageTimestamp(event, msg) 76 | event.AddField("record", msg.Record) 77 | } else { 78 | // we've got JSON 79 | event.Timestamp = parseFunctionTimestamp(msg, jsonRecord) 80 | switch data := jsonRecord["data"].(type) { 81 | case map[string]interface{}: 82 | // data key contains a map, likely emitted by a Beeline's libhoney, so add the fields from it 83 | event.Add(data) 84 | default: 85 | // data is not a map, so treat the record as flat JSON adding all keys as fields 86 | event.Add(jsonRecord) 87 | } 88 | event.SampleRate = parseSampleRate(jsonRecord) 89 | } 90 | default: 91 | // In the case of platform.start and platform.report messages, msg.Record 92 | // will be a map[string]interface{}. 93 | event.Timestamp = parseMessageTimestamp(event, msg) 94 | event.Add(msg.Record) 95 | } 96 | event.Metadata, _ = event.Fields()["name"] 97 | event.SendPresampled() 98 | log.Debug("handler - event enqueued") 99 | } 100 | } 101 | } 102 | 103 | // parseMessageTimestamp is a helper function that tries to parse the timestamp from the 104 | // log event payload. If it cannot parse the timestamp, it returns the current timestamp. 105 | func parseMessageTimestamp(event *libhoney.Event, msg LogMessage) time.Time { 106 | log.Debug("parseMessageTimestamp") 107 | ts, err := time.Parse(time.RFC3339, msg.Time) 108 | if err != nil { 109 | event.AddField("lambda_extension.time", msg.Time) 110 | return time.Now() 111 | } 112 | return ts 113 | } 114 | 115 | func parseSampleRate(body map[string]interface{}) uint { 116 | rate, ok := body["samplerate"] 117 | var foundRate int 118 | 119 | if ok { 120 | // samplerate may be a float (e.g. 43.23), integer (e.g. 54) or a string (e.g. "43") 121 | switch sampleRate := rate.(type) { 122 | case float64: 123 | foundRate = int(sampleRate) 124 | case int64: 125 | foundRate = int(sampleRate) 126 | case string: 127 | if d, err := strconv.Atoi(sampleRate); err == nil { 128 | foundRate = d 129 | } 130 | } 131 | } 132 | if foundRate < 1 { 133 | return 1 134 | } 135 | return uint(foundRate) 136 | } 137 | 138 | // parseFunctionTimestamp is a helper function that will return a timestamp for a function log message. 139 | // There are some precedence rules: 140 | // 141 | // 1. Look for a "time" field from a libhoney transmission in the message body. 142 | // 2. Look for a "timestamp" field in the message body. 143 | // 3. If not present, look for a "duration_ms" field and subtract it from the log event 144 | // timestamp. 145 | // 4. If neither are present, just use the log timestamp. 146 | func parseFunctionTimestamp(msg LogMessage, body map[string]interface{}) time.Time { 147 | log.Debug("parseFunctionTimestamp") 148 | 149 | libhoneyTs, ok := body["time"] 150 | if ok { 151 | strLibhoneyTs, okStr := libhoneyTs.(string) 152 | if okStr { 153 | parsed, err := time.Parse(time.RFC3339, strLibhoneyTs) 154 | if err == nil { 155 | log.Debug("Timestamp from 'time'") 156 | return parsed 157 | } 158 | } 159 | } 160 | 161 | ts, ok := body["timestamp"] 162 | if ok { 163 | strTs, okStr := ts.(string) 164 | if okStr { 165 | parsed, err := time.Parse(time.RFC3339, strTs) 166 | if err == nil { 167 | log.Debug("Timestamp from 'timestamp'") 168 | return parsed 169 | } 170 | } 171 | } 172 | 173 | // parse the logs API event time in case we need it. If it's invalid, just take the time now. 174 | messageTime, err := time.Parse(time.RFC3339, msg.Time) 175 | if err != nil { 176 | log.Debug("Unable to parse message's Time, defaulting to Now()") 177 | messageTime = time.Now() 178 | } else { 179 | log.Debug("Using message's Time field.") 180 | } 181 | 182 | dur, ok := body["duration_ms"] 183 | if ok { 184 | // duration_ms may be a float (e.g. 43.23), integer (e.g. 54) or a string (e.g. "43") 185 | switch duration := dur.(type) { 186 | case float64: 187 | if d, err := time.ParseDuration(fmt.Sprintf("%.4fms", duration)); err == nil { 188 | log.Debug("Timestamp computed from a float64 'duration_ms'") 189 | return messageTime.Add(-1 * d) 190 | } 191 | case int64: 192 | log.Debug("Timestamp computed from an int64 'duration_ms'") 193 | return messageTime.Add(-1 * (time.Duration(duration) * time.Millisecond)) 194 | case string: 195 | if d, err := strconv.ParseFloat(duration, 64); err == nil { 196 | log.Debug("Timestamp computed from a string 'duration_ms'") 197 | return messageTime.Add(-1 * (time.Duration(d) * time.Millisecond)) 198 | } 199 | } 200 | } 201 | 202 | return messageTime 203 | } 204 | 205 | // StartLogsReceiver starts a small HTTP server on the specified port. 206 | // The server receives log messages in AWS Lambda's [Logs API message format] 207 | // (JSON array of messages) and the handler will send them to Honeycomb 208 | // as events with the eventCreator provided as client. 209 | // 210 | // When running in Lambda, the extension's subscription to log types will 211 | // result in the Lambda Logs API publishing log messages to this receiver. 212 | // 213 | // When running in localMode, the server will be started for manual posting of 214 | // log messages to the specified port for testing. 215 | // 216 | // [Logs API message format]: https://docs.aws.amazon.com/lambda/latest/dg/runtimes-logs-api.html#runtimes-logs-api-msg 217 | func StartLogsReceiver(port int, client eventCreator) { 218 | mux := http.NewServeMux() 219 | mux.HandleFunc("/", handler(client)) 220 | server := &http.Server{ 221 | Addr: fmt.Sprintf("0.0.0.0:%d", port), 222 | Handler: mux, 223 | } 224 | log.Info("Logs server listening on port ", port) 225 | log.Fatal(server.ListenAndServe()) 226 | } 227 | -------------------------------------------------------------------------------- /logsapi/server_test.go: -------------------------------------------------------------------------------- 1 | package logsapi 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | "net/http/httptest" 9 | "testing" 10 | "time" 11 | 12 | libhoney "github.com/honeycombio/libhoney-go" 13 | "github.com/honeycombio/libhoney-go/transmission" 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | var ( 18 | epochTimestamp = "1970-01-01T01:01:01.010Z" 19 | christmasTimestamp = "2020-12-25T12:34:56.789Z" 20 | 21 | platformStartMessage = LogMessage{ 22 | Time: "2020-11-03T21:10:25.133Z", 23 | Type: "platform.start", 24 | Record: map[string]string{ 25 | "requestId": "6d67e385-053d-4622-a56f-b25bcef23083", 26 | "version": "$LATEST", 27 | }, 28 | } 29 | 30 | nonJsonFunctionMessage = LogMessage{ 31 | Time: "2020-11-03T21:10:25.150Z", 32 | Type: "function", 33 | Record: "A basic message to STDOUT", 34 | } 35 | 36 | functionMessageWithStringDurationNoTimestamp = LogMessage{ 37 | Time: "2020-11-03T21:10:25.150Z", 38 | Type: "function", 39 | Record: "{\"foo\": \"bar\", \"duration_ms\": \"54\"}", 40 | } 41 | 42 | functionMessageWithIntDurationNoTimestamp = LogMessage{ 43 | Time: "2020-11-03T21:10:25.150Z", 44 | Type: "function", 45 | Record: "{\"foo\": \"bar\", \"duration_ms\": 54}", 46 | } 47 | 48 | functionMessageWithFloatDurationNoTimestamp = LogMessage{ 49 | Time: "2020-11-03T21:10:25.150Z", 50 | Type: "function", 51 | Record: "{\"foo\": \"bar\", \"duration_ms\": 54.43}", 52 | } 53 | 54 | functionMessageWithTimestamp = LogMessage{ 55 | Time: "2020-11-03T21:10:25.150Z", 56 | Type: "function", 57 | Record: "{\"foo\": \"bar\", \"duration_ms\": 54, \"timestamp\": \"2020-11-03T21:10:25.090Z\"}", 58 | } 59 | 60 | functionMessageFromLibhoneyTransmission = LogMessage{ 61 | Time: epochTimestamp, 62 | Type: "function", 63 | // 🎄 64 | Record: `{"time": "2020-12-25T12:34:56.789Z", "samplerate": 1, "data": {"foo": "bar", "duration_ms": 54} }`, 65 | } 66 | 67 | functionMessageJsonAndDataIsNotMappable = LogMessage{ 68 | Time: epochTimestamp, 69 | Type: "function", 70 | Record: `{"timestamp": "2020-12-25T12:34:56.789Z", "data": "an android" }`, 71 | } 72 | 73 | logMessages = []LogMessage{ 74 | platformStartMessage, 75 | nonJsonFunctionMessage, 76 | functionMessageWithStringDurationNoTimestamp, 77 | functionMessageWithIntDurationNoTimestamp, 78 | functionMessageWithTimestamp, 79 | functionMessageFromLibhoneyTransmission, 80 | functionMessageJsonAndDataIsNotMappable, 81 | } 82 | ) 83 | 84 | func postMessages(t *testing.T, messages []LogMessage) []*transmission.Event { 85 | rr := httptest.NewRecorder() 86 | b, err := json.Marshal(messages) 87 | if err != nil { 88 | t.Error(err) 89 | } 90 | req, err := http.NewRequest("POST", "/", bytes.NewBuffer(b)) 91 | if err != nil { 92 | t.Error(err) 93 | } 94 | testTx := &transmission.MockSender{} 95 | client, _ := libhoney.NewClient(libhoney.ClientConfig{ 96 | Transmission: testTx, 97 | APIKey: "blah", 98 | }) 99 | handler(client).ServeHTTP(rr, req) 100 | if status := rr.Code; status != http.StatusOK { 101 | t.Errorf("handler returned wrong status code: got %v want %v", 102 | status, http.StatusOK) 103 | } 104 | return testTx.Events() 105 | } 106 | 107 | func TestLogMessage(t *testing.T) { 108 | events := postMessages(t, logMessages) 109 | 110 | assert.Equal(t, 7, len(events)) 111 | 112 | assert.Equal(t, "platform.start", events[0].Data["lambda_extension.type"]) 113 | assert.Equal(t, "function", events[1].Data["lambda_extension.type"]) 114 | assert.Equal(t, "function", events[2].Data["lambda_extension.type"]) 115 | assert.Equal(t, "function", events[3].Data["lambda_extension.type"]) 116 | 117 | assert.Equal(t, "$LATEST", events[0].Data["version"]) 118 | assert.Equal(t, "A basic message to STDOUT", events[1].Data["record"]) 119 | assert.Equal(t, "bar", events[2].Data["foo"]) 120 | assert.Equal(t, "bar", events[5].Data["foo"]) 121 | assert.Equal(t, "an android", events[6].Data["data"]) 122 | } 123 | 124 | func TestLogMessageFromLibhoneyTransmission(t *testing.T) { 125 | events := postMessages(t, []LogMessage{ 126 | { 127 | Time: epochTimestamp, 128 | Type: "function", 129 | // 🎄 130 | Record: `{"time": "2020-12-25T12:34:56.789Z", "samplerate": 1, "data": {"foo": "bar", "duration_ms": 54}, "foo": "BOGUS", "duration_ms": "ALSO BOGUS" }`, 131 | }, 132 | }) 133 | 134 | parsedEvent := events[0] 135 | 136 | ts, _ := time.Parse(time.RFC3339, christmasTimestamp) 137 | assert.Equal(t, 138 | ts.String(), 139 | parsedEvent.Timestamp.String(), 140 | "Want: 🎄! Do not want: epoch. The event's time should be from the time key within the Transmission JSON, not the Lambda Function's log timestamp.", 141 | ) 142 | assert.Equal(t, "bar", parsedEvent.Data["foo"], "The foo and its value should have been found under the data key within the Transmission JSON.") 143 | assert.Equal(t, float64(54), parsedEvent.Data["duration_ms"], "The duration should have been found under the data key within the Transmission JSON.") 144 | } 145 | 146 | func TestLogMessageJsonWithUnmappableData(t *testing.T) { 147 | events := postMessages(t, []LogMessage{functionMessageJsonAndDataIsNotMappable}) 148 | 149 | parsedEvent := events[0] 150 | 151 | assert.Equal(t, "an android", parsedEvent.Data["data"], "The Data map on the Event should contain a field named 'data' with a single value.") 152 | } 153 | 154 | func TestTimestampsFunctionMessageNoJson(t *testing.T) { 155 | events := postMessages(t, []LogMessage{nonJsonFunctionMessage}) 156 | event := events[0] 157 | 158 | ts, _ := time.Parse(time.RFC3339, "2020-11-03T21:10:25.150Z") 159 | assert.Equal(t, ts.String(), event.Timestamp.String()) 160 | } 161 | 162 | func TestTimestampsPlatformMessage(t *testing.T) { 163 | events := postMessages(t, []LogMessage{platformStartMessage}) 164 | event := events[0] 165 | 166 | // try to parse the timestamp from the Time field of a platform message 167 | ts, err := time.Parse(time.RFC3339, "2020-11-03T21:10:25.133Z") 168 | if err != nil { 169 | assert.Fail(t, "Could not parse timestamp") 170 | } 171 | assert.Equal(t, ts.String(), event.Timestamp.String()) 172 | } 173 | 174 | func TestTimestampsFunctionMessageWithTimestamp(t *testing.T) { 175 | events := postMessages(t, []LogMessage{functionMessageWithTimestamp}) 176 | event := events[0] 177 | 178 | // try to parse the timestamp from the event body of a function message 179 | ts, err := time.Parse(time.RFC3339, "2020-11-03T21:10:25.090Z") 180 | if err != nil { 181 | assert.Fail(t, "Could not parse timestamp") 182 | } 183 | assert.Equal(t, ts.String(), event.Timestamp.String()) 184 | } 185 | 186 | func TestTimestampsFunctionMessageWithDuration(t *testing.T) { 187 | events := postMessages(t, []LogMessage{ 188 | functionMessageWithStringDurationNoTimestamp, 189 | functionMessageWithIntDurationNoTimestamp, 190 | }) 191 | 192 | // when no timestamp is present in the body, take the event timestamp and subtract duration 193 | for _, event := range events { 194 | ts, err := time.Parse(time.RFC3339, "2020-11-03T21:10:25.150Z") 195 | if err != nil { 196 | assert.Fail(t, "Could not parse timestamp") 197 | } 198 | d := 54 * time.Millisecond 199 | ts = ts.Add(-1 * d) 200 | assert.Equal(t, ts.String(), event.Timestamp.String()) 201 | } 202 | 203 | events = postMessages(t, []LogMessage{functionMessageWithFloatDurationNoTimestamp}) 204 | event := events[0] 205 | 206 | ts, err := time.Parse(time.RFC3339, "2020-11-03T21:10:25.150Z") 207 | if err != nil { 208 | assert.Fail(t, "Could not parse timestamp") 209 | } 210 | d, _ := time.ParseDuration(fmt.Sprintf("%.4fms", 54.43)) 211 | ts = ts.Add(-1 * d) 212 | assert.Equal(t, ts.String(), event.Timestamp.String()) 213 | 214 | } 215 | 216 | func TestLibhoneyEventWithSampleRate(t *testing.T) { 217 | t.Run("integer", func(t *testing.T) { 218 | events := postMessages(t, []LogMessage{{ 219 | Time: epochTimestamp, 220 | Type: "function", 221 | Record: `{"time": "2020-12-25T12:34:56.789Z", "samplerate": 5, "data": {"foo": "bar", "duration_ms": 54} }`, 222 | }}) 223 | event := events[0] 224 | assert.EqualValues(t, 5, event.SampleRate) 225 | }) 226 | t.Run("float", func(t *testing.T) { 227 | events := postMessages(t, []LogMessage{{ 228 | Time: epochTimestamp, 229 | Type: "function", 230 | Record: `{"time": "2020-12-25T12:34:56.789Z", "samplerate": 10.1, "data": {"foo": "bar", "duration_ms": 54} }`, 231 | }}) 232 | event := events[0] 233 | // we round downwards 234 | assert.EqualValues(t, 10, event.SampleRate) 235 | }) 236 | t.Run("string", func(t *testing.T) { 237 | events := postMessages(t, []LogMessage{{ 238 | Time: epochTimestamp, 239 | Type: "function", 240 | Record: `{"time": "2020-12-25T12:34:56.789Z", "samplerate": "11", "data": {"foo": "bar", "duration_ms": 54} }`, 241 | }}) 242 | event := events[0] 243 | assert.EqualValues(t, 11, event.SampleRate) 244 | }) 245 | t.Run("string without a number", func(t *testing.T) { 246 | events := postMessages(t, []LogMessage{{ 247 | Time: epochTimestamp, 248 | Type: "function", 249 | Record: `{"time": "2020-12-25T12:34:56.789Z", "samplerate": "hello", "data": {"foo": "bar", "duration_ms": 54} }`, 250 | }}) 251 | event := events[0] 252 | assert.EqualValues(t, 1, event.SampleRate) 253 | }) 254 | t.Run("bool", func(t *testing.T) { 255 | events := postMessages(t, []LogMessage{{ 256 | Time: epochTimestamp, 257 | Type: "function", 258 | Record: `{"time": "2020-12-25T12:34:56.789Z", "samplerate": true, "data": {"foo": "bar", "duration_ms": 54} }`, 259 | }}) 260 | event := events[0] 261 | assert.EqualValues(t, 1, event.SampleRate) 262 | }) 263 | t.Run("negative number", func(t *testing.T) { 264 | events := postMessages(t, []LogMessage{{ 265 | Time: epochTimestamp, 266 | Type: "function", 267 | Record: `{"time": "2020-12-25T12:34:56.789Z", "samplerate": -12, "data": {"foo": "bar", "duration_ms": 54} }`, 268 | }}) 269 | event := events[0] 270 | assert.EqualValues(t, 1, event.SampleRate) 271 | }) 272 | } 273 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "os" 7 | "os/signal" 8 | "path/filepath" 9 | "syscall" 10 | 11 | logrus "github.com/sirupsen/logrus" 12 | 13 | "github.com/honeycombio/honeycomb-lambda-extension/eventprocessor" 14 | "github.com/honeycombio/honeycomb-lambda-extension/eventpublisher" 15 | "github.com/honeycombio/honeycomb-lambda-extension/extension" 16 | "github.com/honeycombio/honeycomb-lambda-extension/logsapi" 17 | ) 18 | 19 | var ( 20 | version string // Fed in at build with -ldflags "-X main.version=" 21 | config extension.Config // Honeycomb extension configuration 22 | 23 | // extension API configuration 24 | extensionName = filepath.Base(os.Args[0]) 25 | 26 | // when run in local mode, we don't attempt to register the extension or subscribe 27 | // to log events - useful for testing 28 | localMode = false 29 | 30 | // set up logging defaults for our own logging output 31 | log = logrus.WithFields(logrus.Fields{ 32 | "source": "hny-lambda-ext-main", 33 | }) 34 | ) 35 | 36 | func init() { 37 | if version == "" { 38 | version = "dev" 39 | } 40 | 41 | config = extension.NewConfigFromEnvironment() 42 | 43 | logLevel := logrus.InfoLevel 44 | if config.Debug { 45 | logLevel = logrus.DebugLevel 46 | } 47 | logrus.SetLevel(logLevel) 48 | } 49 | 50 | func main() { 51 | flag.BoolVar(&localMode, "localMode", false, "do not attempt to register or subscribe") 52 | flag.Parse() 53 | 54 | ctx, cancel := context.WithCancel(context.Background()) 55 | 56 | // exit cleanly on SIGTERM or SIGINT 57 | exit := make(chan os.Signal, 1) 58 | signal.Notify(exit, os.Interrupt, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT) 59 | go func() { 60 | sig := <-exit 61 | log.Warn("Received ", sig, " - shutting down.") 62 | cancel() 63 | }() 64 | 65 | // initialize event publisher client 66 | eventpublisherClient, err := eventpublisher.New(config, version) 67 | if err != nil { 68 | log.Warn("Could not initialize event publisher", err) 69 | } 70 | 71 | // initialize Logs API HTTP server 72 | go logsapi.StartLogsReceiver(config.LogsReceiverPort, eventpublisherClient) 73 | 74 | // if running in localMode, wait on the context to be cancelled, 75 | // then early return main() to end the process 76 | if localMode { 77 | select { 78 | case <-ctx.Done(): 79 | return 80 | } 81 | } 82 | 83 | // --- Lambda Runtime Activity --- 84 | 85 | // register with Extensions API 86 | extensionClient := extension.NewClient(config.RuntimeAPI, extensionName) 87 | res, err := extensionClient.Register(ctx) 88 | if err != nil { 89 | log.Panic("Could not register extension", err) 90 | } 91 | log.Debug("Response from register: ", res) 92 | 93 | // subscribe to Lambda log streams 94 | subscription, err := logsapi.Subscribe(ctx, config, extensionClient.ExtensionID) 95 | if err != nil { 96 | log.Warn("Could not subscribe to events: ", err) 97 | } 98 | log.Debug("Response from subscribe: ", subscription) 99 | 100 | eventprocessor.New(extensionClient, eventpublisherClient).Run(ctx, cancel) 101 | } 102 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | artifact_dir=~/artifacts/linux 6 | for arch in x86_64 arm64; do 7 | if [ ! -f "${artifact_dir}/extension-${arch}.zip" ]; then 8 | echo "${arch} extension does not exist, cannot publish." 9 | exit 1; 10 | fi 11 | done 12 | 13 | VERSION="${CIRCLE_TAG:-$(make version)}" 14 | # lambda layer names must match a regex: [a-zA-Z0-9-_]+)|[a-zA-Z0-9-_]+ 15 | # turn periods into dashes and cry into your coffee 16 | VERSION=$(echo ${VERSION} | tr '.' '-') 17 | 18 | EXTENSION_NAME="honeycomb-lambda-extension" 19 | 20 | # Region list update from AWS Lambda pricing page as of 2023/02/27 21 | # Commented out lines are listed on available but require opt-in before we can publish to it. 22 | # 23 | # regions with x86_64 only support 24 | REGIONS_NO_ARM=( 25 | ap-southeast-4 26 | eu-central-2 27 | eu-south-2 28 | me-central-1 29 | ) 30 | # Regions with x86_64 & arm64 31 | REGIONS_WITH_ARM=( 32 | af-south-1 33 | ap-east-1 34 | ap-northeast-1 35 | ap-northeast-2 36 | ap-northeast-3 37 | ap-south-1 38 | ap-southeast-1 39 | ap-southeast-2 40 | ap-southeast-3 41 | ca-central-1 42 | eu-central-1 43 | eu-north-1 44 | eu-south-1 45 | eu-west-1 46 | eu-west-2 47 | eu-west-3 48 | me-south-1 49 | sa-east-1 50 | us-east-1 51 | us-east-2 52 | us-west-1 53 | us-west-2 54 | ) 55 | 56 | 57 | results_dir="publishing" 58 | mkdir -p ${results_dir} 59 | 60 | ### x86_64 ### 61 | 62 | layer_name_x86_64="${EXTENSION_NAME}-x86_64-${VERSION}" 63 | 64 | for region in ${REGIONS_WITH_ARM[@]}; do 65 | id="x86_64-${region}" 66 | publish_results_json="${results_dir}/publish-${id}.json" 67 | permit_results_json="${results_dir}/permit-${id}.json" 68 | aws lambda publish-layer-version \ 69 | --layer-name $layer_name_x86_64 \ 70 | --compatible-architectures x86_64 \ 71 | --region $region \ 72 | --zip-file "fileb://${artifact_dir}/extension-x86_64.zip" \ 73 | --no-cli-pager \ 74 | > "${publish_results_json}" 75 | layer_version=`jq -r '.Version' ${publish_results_json}` 76 | aws --region $region lambda add-layer-version-permission --layer-name $layer_name_x86_64 \ 77 | --version-number $layer_version --statement-id "$EXTENSION_NAME-x86_64-$layer_version-$region" \ 78 | --principal "*" --action lambda:GetLayerVersion --no-cli-pager \ 79 | > "${permit_results_json}" 80 | done 81 | 82 | for region in ${REGIONS_NO_ARM[@]}; do 83 | id="x86_64-${region}" 84 | publish_results_json="${results_dir}/publish-${id}.json" 85 | permit_results_json="${results_dir}/permit-${id}.json" 86 | aws lambda publish-layer-version \ 87 | --layer-name $layer_name_x86_64 \ 88 | --region $region \ 89 | --zip-file "fileb://${artifact_dir}/extension-x86_64.zip" \ 90 | --no-cli-pager \ 91 | > "${publish_results_json}" 92 | layer_version=`jq -r '.Version' ${publish_results_json}` 93 | aws --region $region lambda add-layer-version-permission --layer-name $layer_name_x86_64 \ 94 | --version-number $layer_version --statement-id "$EXTENSION_NAME-x86_64-$layer_version-$region" \ 95 | --principal "*" --action lambda:GetLayerVersion --no-cli-pager \ 96 | > "${permit_results_json}" 97 | done 98 | 99 | ### arm64 ### 100 | 101 | layer_name_arm64="${EXTENSION_NAME}-arm64-${VERSION}" 102 | 103 | for region in ${REGIONS_WITH_ARM[@]}; do 104 | id="arm64-${region}" 105 | publish_results_json="${results_dir}/publish-${id}.json" 106 | permit_results_json="${results_dir}/permit-${id}.json" 107 | aws lambda publish-layer-version \ 108 | --layer-name $layer_name_arm64 \ 109 | --compatible-architectures arm64 \ 110 | --region $region \ 111 | --zip-file "fileb://${artifact_dir}/extension-arm64.zip" \ 112 | --no-cli-pager \ 113 | > "${publish_results_json}" 114 | layer_version=`jq -r '.Version' ${publish_results_json}` 115 | aws --region $region lambda add-layer-version-permission --layer-name $layer_name_arm64 \ 116 | --version-number $layer_version --statement-id "$EXTENSION_NAME-arm64-$layer_version-$region" \ 117 | --principal "*" --action lambda:GetLayerVersion --no-cli-pager \ 118 | > "${permit_results_json}" 119 | done 120 | 121 | echo "" 122 | echo "Published Layer Versions:" 123 | echo "" 124 | jq '{ region: (.LayerArn | split(":")[3]), 125 | arch: (.LayerArn | split(":")[6] | split("-")[3]), 126 | arn: .LayerVersionArn 127 | }' publishing/publish-*.json 128 | --------------------------------------------------------------------------------